home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / adatutor / csparts / cspartb3.src < prev    next >
Text File  |  1996-01-30  |  161KB  |  5,206 lines

  1. --::::::::::
  2. --hashmap.bdy
  3. --::::::::::
  4. -- $Source: /nosc/work/abstractions/mapping/RCS/hash_map.bdy,v $
  5. -- $Revision: 1.3 $ -- $Date: 85/02/01 14:48:43 $ -- $Author: ron $
  6.  
  7. with unchecked_deallocation;
  8.  
  9. package body hashed_mapping_pkg is
  10.     
  11.     function equal(c1, c2: component)
  12.     return boolean is
  13.     begin
  14.     return equal(c1.key, c2.key);
  15.     end equal;
  16.     
  17.       
  18.   -- Utilities:
  19.     
  20.     procedure free is new unchecked_deallocation(mapping_rec, mapping);
  21.      
  22.     function make_general_iter(map: mapping)
  23.     return general_iter;
  24.       --| Raises: uninitialized_mapping
  25.       --| Effects:
  26.       --| Create and return a general iterator based on map.  Sets up
  27.       --| map, current and position fields as in the spec.
  28.       --| Raises uninitialized_mapping iff map has not been initialized.
  29.   
  30.     function more(iter: general_iter)
  31.     return boolean;
  32.       --| Effects:
  33.       --| Returns true iff the general iter has not been exhausted, i.e.,
  34.       --| returns not IsEmpty(iter.position).
  35.        
  36.     procedure advance(iter: in out general_iter);
  37.       --| Effects:
  38.       --| Advances iter.position, and if necessary, iter.current to the
  39.       --| next component, as detailed in the spec.  iter.position will
  40.       --| be empty if no more elements remain to be iterated over.
  41.       --| Requires:
  42.       --| iter.position is not null, i.e., caller has determined that iter
  43.       --| was not exhausted before calling advance.
  44.  
  45.  
  46.   -- Constructors:
  47.  
  48.     function create
  49.         return mapping is
  50.         m: mapping;
  51.     begin
  52.         -- deleted because of Decada bug:
  53. --      return new mapping_rec'(size => 0,
  54. --                              buckets => (bucket_range => create));
  55.         m := new mapping_rec; 
  56.         m.size := 0;
  57.         m.all.buckets := (bucket_array'range => create);
  58.         return m;
  59.     end create;
  60.  
  61.     procedure bind(map:   in out mapping;
  62.                    key:   in     key_type;
  63.                    value: in     value_type) is
  64.     idx: bucket_range := hash(key);
  65.     c: component := (key => key, val => value);
  66.     begin
  67.     if IsInList(map.buckets(idx), c) then
  68.         raise already_bound;
  69.     end if;
  70.     
  71.     map.buckets(idx) := attach(c, map.buckets(idx));
  72.     map.size := map.size + 1;
  73.     
  74.     exception
  75.         when constraint_error =>       -- null dereference
  76.         raise uninitialized_mapping;
  77.     end bind;
  78.  
  79.     procedure unbind(map: in out mapping;
  80.                      key: in     key_type) is
  81.     idx: bucket_range := hash(key);
  82.     tmpc: component;
  83.     begin
  84.     tmpc.key := key;   -- don't need a value, equality just tests keys
  85.     DeleteItem(map.buckets(idx), tmpc);
  86.     map.size := map.size - 1;
  87.     
  88.     exception
  89.         when ItemNotPresent =>
  90.             raise not_bound;
  91.     when constraint_error =>       -- null dereference
  92.         raise uninitialized_mapping;
  93.     end unbind;
  94.       
  95.     function copy(map: mapping)
  96.     return mapping is
  97.     new_map: mapping;
  98.     begin
  99.     if map = null then raise uninitialized_mapping; end if;
  100.     
  101.     new_map := new mapping_rec;
  102.     new_map.size := map.size;
  103.     for idx in bucket_range loop
  104.         new_map.buckets(idx) := copy(map.buckets(idx));
  105.     end loop;
  106.     return new_map;
  107.     end copy;
  108.   
  109.  
  110.   -- Query Operations:
  111.  
  112.     function is_empty(map: mapping)
  113.         return boolean is
  114.     begin
  115.     return map.size = 0;
  116.     exception
  117.     when constraint_error =>       -- null dereference
  118.         raise uninitialized_mapping;
  119.     end is_empty;
  120.  
  121.     function size(map: mapping)
  122.         return natural is
  123.     begin
  124.     return map.size;
  125.     exception
  126.     when constraint_error =>       -- null dereference
  127.         raise uninitialized_mapping;
  128.     end size;
  129.  
  130.     function is_bound(map: mapping;
  131.                       key: key_type)
  132.     return boolean is
  133.     tmpc: component;
  134.     begin
  135.     tmpc.key := key;   -- don't need a value, equality just tests keys
  136.     return IsInList(map.buckets(hash(key)), tmpc);
  137.     exception
  138.         when constraint_error =>     -- null dereference
  139.         raise uninitialized_mapping;
  140.     end is_bound;
  141.     
  142.     function fetch(map: mapping;
  143.                    key: key_type)
  144.     return value_type is
  145.     buck: list;
  146.     begin
  147.     buck := map.buckets(hash(key));
  148.  
  149.     while not IsEmpty(buck) loop
  150.             if equal(key, FirstValue(buck).key) then
  151.         return FirstValue(buck).val;
  152.         end if;
  153.         buck := tail(buck);
  154.     end loop;
  155.     raise not_bound;
  156.     
  157.     exception
  158.     when constraint_error =>       -- null dereference
  159.         raise uninitialized_mapping;
  160.     end fetch;
  161.  
  162.  
  163.   -- Iterators:
  164.   
  165.     function make_keys_iter(map: mapping)
  166.         return keys_iter is
  167.     begin
  168.     return keys_iter(make_general_iter(map));
  169.     end make_keys_iter;
  170.  
  171.     function more(iter: keys_iter)
  172.         return boolean is
  173.     begin
  174.     return more(general_iter(iter));
  175.     end more;
  176.  
  177.     procedure next(iter: in out keys_iter;
  178.                    key:  out    key_type) is
  179.     begin
  180.     key := FirstValue(iter.position).key;
  181.     advance(general_iter(iter));
  182.     exception
  183.         when EmptyList =>
  184.         raise no_more;
  185.     end next;
  186.  
  187.     function make_values_iter(map: mapping)
  188.     return values_iter is
  189.     begin
  190.     return values_iter(make_general_iter(map));
  191.     end make_values_iter;
  192.  
  193.     function more(iter: values_iter)
  194.     return boolean is
  195.     begin
  196.     return more(general_iter(iter));
  197.     end more;
  198.     
  199.     procedure next(iter: in out values_iter;
  200.            val:  out    value_type) is
  201.     begin
  202.     val := FirstValue(iter.position).val;
  203.     advance(general_iter(iter));
  204.     exception
  205.         when EmptyList =>
  206.         raise no_more;
  207.     end next;
  208.     
  209.     function make_bindings_iter(map: mapping)
  210.     return bindings_iter is
  211.     begin
  212.         return bindings_iter(make_general_iter(map));
  213.     end make_bindings_iter;
  214.   
  215.     function more(iter: bindings_iter)
  216.     return boolean is
  217.     begin
  218.     return more(general_iter(iter));
  219.     end more;
  220.     
  221.     procedure next(iter: in out bindings_iter;
  222.            key:  out    key_type;
  223.            val:  out    value_type) is
  224.     comp: component;
  225.     begin
  226.     comp := FirstValue(iter.position);
  227.     key := comp.key;
  228.     val := comp.val;
  229.     advance(general_iter(iter));
  230.     exception
  231.         when EmptyList =>
  232.         raise no_more;
  233.     end next;
  234.     
  235.     
  236.   -- Heap management:
  237.  
  238.     procedure destroy(m: in out mapping) is
  239.     begin
  240.         for i in bucket_range loop
  241.             destroy(m.buckets(i));
  242.         end loop;
  243.         free(m);
  244.     exception
  245.         when constraint_error =>    -- m is null
  246.         return;
  247.     end destroy;
  248.  
  249.  
  250. -- Utilities:
  251.     
  252.     function make_general_iter(map: mapping)
  253.     return general_iter is
  254.     iter: general_iter;
  255.     begin
  256.     if map = null then raise uninitialized_mapping; end if;
  257.     
  258.     for idx in bucket_range loop
  259.         if not IsEmpty(map.buckets(idx)) then
  260.         iter.map := map;
  261.         iter.current := idx;
  262.         iter.position := map.buckets(idx);
  263.         return iter;
  264.         end if;
  265.     end loop;
  266.     
  267.     iter.position := create;   -- no elements, makes next(iter) false.
  268.     return iter;
  269.     end make_general_iter;
  270.     
  271.     function more(iter: general_iter)
  272.     return boolean is
  273.     begin
  274.     return not IsEmpty(iter.position);
  275.     end more;
  276.     
  277.     procedure advance(iter: in out general_iter) is
  278.     begin
  279.     iter.position := tail(iter.position);
  280.         if IsEmpty(iter.position) and then iter.current /= bucket_range'last then
  281.         for idx in iter.current + 1..bucket_range'last loop
  282.         if not IsEmpty(iter.map.buckets(idx)) then
  283.             iter.current := idx;
  284.             iter.position := iter.map.buckets(idx);
  285.             return;
  286.         end if;
  287.         end loop;
  288.         end if;        
  289.         -- At this point, IsEmpty(iter.position) => not more(iter)
  290.     end advance;
  291.     
  292. end hashed_mapping_pkg;
  293. --::::::::::
  294. --ltrees.bdy
  295. --::::::::::
  296. with unchecked_deallocation;
  297. package body Labeled_Trees is
  298.  
  299. ----------------------------------------------------------------------------
  300. --                   Local Subprograms
  301. ----------------------------------------------------------------------------
  302.  
  303. procedure Free is new unchecked_deallocation (Node, Tree);
  304.  
  305. function equal (
  306.        X :in     Label_Type;
  307.        Y :in     Label_Type
  308. ) return boolean is 
  309.  
  310. begin
  311.     return (not (X < Y))  and  (not (Y < X));
  312. end equal;
  313.  
  314. ------------------------------------------------------------------------------
  315.  
  316. procedure Internal_Is_Label_In_Tree (
  317.    T         :in      Tree;
  318.    L         :in      Label_Type;
  319.    Parent    :in out Tree;
  320.    Present   :   out boolean;
  321.    recursed  :in out boolean
  322. ) is
  323. begin
  324.     --| OVERVIEW
  325.     --| This procedure is used so that
  326.     --| Is_Label_In_Tree (T, L, Subtree, Present) returns more useful 
  327.     --| information.  If the label L is not in the tree then Subtree is
  328.     --| the root of the tree where L should be inserted.  If L is in 
  329.     --| the tree then Subtree is the root of the tree where L is.
  330.     --| This procedure is necessary because in Is_Label_In_Tree has Subtree
  331.     --| as an out parameter not as in out.
  332.  
  333.     --| The variable Recursed is used to indicate whether we have called
  334.     --| the procedure recursively.  It is used when T is null.  If T is
  335.     --| null and we haven't called recursively then T's parent is null.
  336.     --| If T is null and we have called the procedure recusively then
  337.     --| T's parent is not null.
  338.  
  339.     if T = null then
  340.         Present := false;
  341.         if not Recursed then
  342.             Parent := null;
  343.         end if;
  344.     elsif L < T.Label then
  345.         Parent := T;
  346.         recursed := true;
  347.         Internal_Is_Label_In_Tree (T.Left_Child, L, Parent, Present, Recursed);
  348.     elsif T.Label < L then
  349.         Parent := T;
  350.         Recursed := true;
  351.         Internal_Is_Label_In_Tree (
  352.           T.Right_Child , L, Parent, Present, Recursed
  353.                                   );
  354.     else
  355.         Parent := T;
  356.         Present := true;
  357.     end if;
  358. end Internal_Is_Label_In_Tree;
  359.  
  360. ------------------------------------------------------------------------------
  361.  
  362. function Pre_Order_Generate (
  363.           T :in Tree
  364. ) return  Node_Order.List is
  365.  
  366.  
  367. --| This routine generates a list of pointers to nodes in the tree t.
  368. --| The list of nodes is a pre order list of the nodes of the tree.
  369.  
  370.     L : Node_Order.List;
  371. begin 
  372.     L := Node_Order.Create;
  373.     if T /= null then
  374.         Node_Order.Attach (L, T);
  375.         Node_Order.Attach (L, Pre_Order_Generate (T.Left_Child));
  376.         Node_Order.Attach (L, Pre_Order_Generate (T.Right_Child));
  377.     end if;
  378.     return L;
  379. end Pre_Order_Generate;
  380.  
  381. ------------------------------------------------------------------------------
  382.  
  383. function Post_Order_Generate (
  384.           T :in Tree
  385. ) return  Node_Order.List is
  386.  
  387.  
  388. --| This routine generates a list of pointers to nodes in the tree t.
  389. --| The list is a post ordered list of nodes of the tree.
  390.  
  391.     L : Node_Order.List;
  392. begin 
  393.     L := Node_Order.Create;
  394.     if T /= null then
  395.         L := Post_Order_Generate (T.Left_Child);
  396.         Node_Order.Attach (L, Post_Order_Generate (T.Right_Child));
  397.         Node_Order.Attach (L, T);
  398.     end if;
  399.     return L;
  400. end Post_Order_Generate;
  401.  
  402. ------------------------------------------------------------------------------
  403.  
  404. function In_Order_Generate (
  405.           T :in Tree
  406. ) return  Node_Order.List is
  407.  
  408.  
  409. --| This routine generates a list of pointers to nodes in the tree t.
  410. --| The list is ordered with respect to the order of the nodes in the tree.
  411. --| The nodes in the list are such the element 1 < element 2 < .... 
  412. --| element (n - 1) < element (n).  Where < is passed in .
  413.  
  414.     L : Node_Order.List;
  415. begin 
  416.     L := Node_Order.Create;
  417.     if T /= null then
  418.         L := In_Order_Generate (T.Left_Child);
  419.         Node_Order.Attach (L, T);
  420.         Node_Order.Attach (L, In_Order_Generate (T.Right_Child));
  421.     end if;
  422.     return L;
  423. end In_Order_Generate;
  424.  
  425. ------------------------------------------------------------------------------
  426.  
  427.  
  428.  
  429. ------------------------------------------------------------------------------
  430. --                    Visible Subprograms
  431. ------------------------------------------------------------------------------
  432.  
  433. ------------------------------------------------------------------------------
  434.  
  435. function Create  return Tree is
  436.  
  437. begin
  438.     return null;
  439. end;
  440.  
  441. ------------------------------------------------------------------------------
  442.  
  443. procedure Destroy_Deep_Tree (
  444.   T :in out Tree
  445. ) is
  446.  
  447. begin
  448.     --| ALGORITHM
  449.     --| Walk over the tree destroying the value, the label, and then the node
  450.     --| itself.  Do this in post order.  This means destroy the left child
  451.     --| destroy the right child and then destroy the node.
  452.  
  453.     if T /= null then
  454.        Destroy_Deep_Tree (T.Left_Child);
  455.        Destroy_Deep_Tree (T.Right_Child);
  456.        Dispose_Label (T.Label);
  457.        Dispose_Value (T.Value);
  458.        Destroy_Tree (T);
  459.     end if;
  460. end;
  461.  
  462. ------------------------------------------------------------------------------
  463.  
  464. procedure Destroy_Tree ( T :in out Tree) is
  465.  
  466.  
  467. begin
  468.     --| OVERVIEW
  469.     --| This procedure recursively destroys the tree T.
  470.     --|  1.  It destroy the Left_Child of T
  471.     --|  2.  It then destroys the Right_Child of T.
  472.     --|  3.  It then destroy the root T and set T to be null.
  473.  
  474.     if T /= null then
  475.         Destroy_Tree (T.Left_Child);
  476.         Destroy_Tree (T.Right_Child);
  477.         Free (T);
  478.     end if;
  479. end Destroy_Tree;
  480.  
  481. ------------------------------------------------------------------------------
  482.  
  483. function Fetch_Value (         --| Get the value of the node with the given 
  484.                                --| value.
  485.        T :in     Tree;         --| The tree which contains the node.
  486.        L :in     Label_Type    --| The label of the node.
  487. ) return Value_Type is
  488.  
  489. begin
  490.     if T = null then 
  491.         raise Label_Not_Present;
  492.     elsif L < T.Label then
  493.         return Fetch_Value (T.Left_Child, L);
  494.     elsif T.Label < L then
  495.         return Fetch_Value (T.Right_Child, L);
  496.     else
  497.         return T.Value;
  498.     end if;               
  499. end Fetch_Value;
  500.      
  501. --------------------------------------------------------------------------
  502.  
  503. function Fetch_Value (  --| Return the value stored at the root node
  504.                         --| of the given tree.
  505.          T :in Tree
  506. ) return Value_Type is
  507.  
  508. begin
  509.     if T = null then
  510.        raise Tree_Is_Empty;    
  511.     else
  512.        return T.Value;
  513.     end if;
  514. end Fetch_Value;
  515.   
  516. --------------------------------------------------------------------------
  517.  
  518. procedure Forward (        --| Advances the iterator to the next node in
  519.                            --| the iteration. 
  520.   I :in out Tree_Iter      --| Iterator being advance.
  521. ) is
  522. begin
  523.     Node_Order.Forward (I.State);
  524. end Forward;
  525.  
  526. ------------------------------------------------------------------------------
  527.  
  528. function Get_Tree (         --| Get the tree whose root is labelled L.
  529.        T :in    Tree;       --| Tree which contains the label L.
  530.        L :in    Label_Type  --| The label being searched for.
  531. ) return Tree is
  532.  
  533. begin
  534.     if T = null then
  535.         raise Label_Not_Present;
  536.     elsif L < T.Label then
  537.         return Get_Tree (T.Left_Child, L);
  538.     elsif T.Label < L then
  539.         return Get_Tree (T.Right_Child, L);
  540.     else
  541.        return T;
  542.     end if;
  543. end Get_Tree;
  544.  
  545. ------------------------------------------------------------------------------
  546.  
  547. procedure Insert_Node (       --| This procedure inserts a node into
  548.                               --| the tree T with label and value V.
  549.       T  :in out Tree;
  550.       L  :in     Label_Type;
  551.       V  :in     Value_Type
  552. ) is
  553.  
  554. begin
  555.     if T = null then
  556.        T := new Node ' 
  557.             ( Value => V, Label => L, Left_Child => null, Right_Child => null);
  558.     elsif L < T.Label then
  559.        Insert_Node (T.Left_Child, L, V);
  560.     elsif T.Label < L then
  561.        Insert_Node (T.Right_Child, L, V);
  562.     elsif T.Label = L then
  563.        raise Label_Already_Exists_In_Tree;
  564.     end if;
  565. end Insert_Node; 
  566.     
  567. ------------------------------------------------------------------------------
  568.  
  569. function Is_Empty (        --| Returns true if the tree is empty false
  570.                            --| otherwise.
  571.          T :in     Tree
  572. ) return boolean is
  573. begin
  574.     return T = null;
  575. end Is_Empty;
  576.  
  577. ------------------------------------------------------------------------------
  578.  
  579. function Is_Label_In_Tree (            --| Is the given label in the given
  580.                                        --| tree.
  581.          T :in    Tree;                --| The tree being searched.
  582.          L :in    Label_Type           --| The label being searched for.
  583. ) return boolean is
  584. begin
  585.     if T = null then
  586.          return false;
  587.     elsif L < T.Label then
  588.          return Is_Label_In_Tree (T.Left_Child, L);
  589.     elsif T.Label < L then
  590.          return Is_Label_In_Tree (T.Right_Child, L);
  591.     else
  592.         return true;
  593.     end if;
  594. end Is_Label_In_Tree;
  595.  
  596. ------------------------------------------------------------------------------
  597.  
  598. procedure Is_Label_In_Tree (            --| Checks if the given label is 
  599.                                         --| in the given tree.
  600.            T       :in     Tree;        --| Tree being searched.
  601.            L       :in     Label_Type;  --| Label being searched for.
  602.            Subtree :   out Tree;        --| Subtree which is contains label.
  603.            Present :   out boolean      --| True if label is in tree, false
  604.                                         --| if not.
  605. ) is
  606.     Recursed          :boolean := false;
  607.     Internal_Subtree  :Tree;    -- This variable is needed because
  608.                                 -- in Internal_Is_Label subtree is an in out
  609.                                 -- parameter.                   
  610.       
  611. begin
  612.      --| Sets the variable Present to true if the given label is in the given 
  613.      --| tree. Also sets the variable Subtree to 
  614.      --| the root of the subtree which contains the label.  If L isn't in the
  615.      --| tree then Subtree is the root of the tree where label should be
  616.      --| inserted.  This internal routine is called so that if L isn't in T
  617.      --| then Subtree will be the root of the tree where L should be inserted.
  618.      --| In order to do this we need the extra variable Recursed.
  619.  
  620.     Internal_Is_Label_In_Tree (T, L, Internal_Subtree, Present, Recursed);
  621.     Subtree := Internal_Subtree;
  622. end Is_Label_In_Tree;
  623.  
  624. ----------------------------------------------------------------------------
  625.  
  626. function Iterator_Label (  --| Returns the label of the node corresponding
  627.                            --| to the iterator.
  628.   I :in      Tree_Iter     --| Iterator.
  629. ) return Label_Type is
  630.     T :Tree;
  631. begin
  632.     T := Node_Order.CellValue (I.State);
  633.     return T.Label;
  634. end Iterator_Label;
  635.  
  636. -----------------------------------------------------------------------------
  637.  
  638. function Iterator_Value (  --| Returns the value of the node corresponding
  639.                            --| to the iterator.
  640.   I :in      Tree_Iter     --| Iterator.
  641. ) return Value_Type is
  642.     T :Tree;
  643. begin
  644.     T := Node_Order.CellValue (I.State);
  645.     return T.Value;
  646. end;
  647.  
  648. -------------------------------------------------------------------------------
  649.  
  650. function Make_Tree (          --| This creates a tree given a label and a  
  651.                               --| value.
  652.        L :in     Label_Type;  --| The label.
  653.        V :in     Value_Type   --| The value.
  654. ) return Tree is
  655.  
  656. begin
  657.      return  new Node ' ( 
  658.                    Value => V, 
  659.                    Label => L, 
  660.                    Left_Child => null,
  661.                    Right_Child => null
  662.                         );
  663. end;
  664.  
  665. -------------------------------------------------------------------------------
  666.  
  667. function Make_Tree_Iter_In  (  --| This sets up an inoder iteration of the 
  668.                                --| nodes of the tree.
  669.         T :in     Tree         --| Tree being iterated over 
  670. ) return Tree_Iter is
  671.  
  672. --| This sets up the iterator for a tree T.
  673. --| The NodeList keeps track of the order of the nodes of T.  The Node_List
  674. --| is computed by first invoking In_Generate of the Left_Child then append
  675. --| the root node to Node_List and then append the result of In_Generate
  676. --| to Node_List.  Since the tree is ordered such that 
  677. --|
  678. --|    Left_Child < root    root < Right_Child 
  679. --| 
  680. --| Node_Order returns the nodes in ascending order.
  681. --|
  682. --| Thus Node_List keeps the list alive for the duration of the iteration
  683. --| operation.  The variable State is the a pointer into the Node_List
  684. --| which is the current place of the iteration.
  685.  
  686.     I :Tree_Iter;
  687. begin
  688.     I.Node_List := Node_Order.Create;
  689.     if T /= null then
  690.         Node_Order.Attach (I.Node_List, In_Order_Generate (T));    
  691.     end if;
  692.     I.State := Node_Order.MakeListIter (I.Node_List);
  693.     return I;    
  694. end Make_Tree_Iter_In;    
  695.  
  696. ------------------------------------------------------------------------------
  697.  
  698. function Make_Tree_Iter_Post (  --| This sets up a postorder iteration of the
  699.                                 --| nodes of the tree.
  700.         T :in     Tree          --| Tree being iterated over 
  701. ) return Tree_Iter is
  702.  
  703. --| A postorder iteration of the tree ( + a b)  where the root is + and 
  704. --| the left child is a and the right child is b will return the nodes
  705. --| in the order a b +.  
  706. --| Node_List is a post_ordered list of the nodes of the tree generated 
  707. --| by Post_Order Generate. Thus Node_List keeps the list alive for the 
  708. --| duration of the iteration operation.  The variable State is the a pointer 
  709. --| into the Node_List which is the current place of the iteration.
  710.  
  711.     I :Tree_Iter;
  712. begin
  713.     I.Node_List := Node_Order.Create;
  714.     if T /= null then
  715.         Node_Order.Attach (I.Node_List, Post_Order_Generate (T));    
  716.     end if;
  717.     I.State := Node_Order.MakeListIter (I.Node_List);
  718.     return I;    
  719. end Make_Tree_Iter_Post;    
  720.  
  721. -----------------------------------------------------------------------------
  722.  
  723. function Make_Tree_Iter_Pre (   --| This sets up an iteration of the nodes
  724.                                 --| of the tree in preorder.  Then nodes
  725.                                 --| of the tree are returned in ascending 
  726.                                 --| order.  
  727.         T :in     Tree          --| Tree being iterated over 
  728. ) return Tree_Iter is
  729.  
  730.  
  731. --| A preorder iteration of the tree ( + a b)  where the root is + and 
  732. --| the left child is a and the right child is b will return the nodes
  733. --| in the order + a b .  
  734. --| Node_List is a pre_ordered list of the nodes of the tree generated 
  735. --| by Pre_Order_Generate. Thus Node_List keeps the list alive for the 
  736. --| duration of the iteration operation.  The variable State is the a pointer 
  737. --| into the Node_List which is the current place of the iteration.
  738.  
  739.     I :Tree_Iter;
  740. begin
  741.     I.Node_List := Node_Order.Create;
  742.     if T /= null then
  743.         Node_Order.Attach (I.Node_List, Pre_Order_Generate (T));    
  744.     end if;
  745.     I.State := Node_Order.MakeListIter (I.Node_List);
  746.     return I;    
  747. end Make_Tree_Iter_Pre;    
  748.  
  749. ------------------------------------------------------------------------------
  750.  
  751. function More (
  752.      I :in Tree_Iter
  753. ) return boolean is
  754.    
  755. begin
  756.     return Node_Order.More (I.State);
  757. end More;
  758.  
  759. ------------------------------------------------------------------------------
  760.  
  761. procedure Next (
  762.           I     :in out Tree_Iter;
  763.           V     :   out Value_Type       
  764. ) is
  765.  
  766.  
  767.     T :Tree;
  768. begin
  769.     --| OVERVIEW    
  770.     --| Next returns the information at the current position in the iterator
  771.     --| and increments the iterator.  This is accomplished by using the iterater
  772.     --| associated with the Node_Order list.  This returns a pointer into the Tree
  773.     --| and then the information found at this node in T is returned.
  774.     Node_Order.Next (I.State, T);
  775.     V := T.Value ;
  776. exception 
  777.     when Node_Order.NoMore => 
  778.       raise No_More;
  779.     when others =>
  780.       raise;
  781. end Next;
  782.  
  783. -----------------------------------------------------------------------------
  784.  
  785. procedure Next ( 
  786.           I :in out Tree_Iter;
  787.           V :   out Value_Type;
  788.           L :   out Label_Type
  789. ) is
  790.  
  791.     T :Tree;
  792. begin
  793.     --| OVERVIEW    
  794.     --| Next returns the information at the current position in the iterator
  795.     --| and increments the iterator.  This is accomplished by using the 
  796.     --| iterater associated with the Node_Order list.  This returns a 
  797.     --| pointer into the Tree and then the information found at this node in 
  798.     --| T is returned.
  799.  
  800.     Node_Order.Next (I.State, T);
  801.     V := T.Value ;
  802.     L := T.Label;
  803.  
  804. exception 
  805.     when Node_Order.NoMore => 
  806.       raise No_More;
  807.     when others =>
  808.       raise;
  809. end Next;
  810.  
  811. -----------------------------------------------------------------------------
  812.  
  813. procedure Store_Value (             
  814.         T :in out Tree;          --| Tree value is being stored in.
  815.         L :in     Label_Type;    --| The label of the node where the 
  816.                                  --| information is being stored.
  817.         V :in     Value_Type     --| The value being stored.
  818. ) is
  819.  
  820. begin
  821.     if T = null then
  822.         raise Label_Not_Present;
  823.     elsif L < T.Label then
  824.         Store_Value (T.Left_Child, L, V);
  825.     elsif T.Label < L then
  826.         Store_Value (T.Right_Child, L, V);
  827.     else
  828.         T.Value := V;
  829.     end if;
  830. end Store_Value; 
  831.  
  832. -------------------------------------------------------------------------------
  833.  
  834. procedure Store_Value (          --| This stores the value V in the root
  835.                                  --| node of the tree T.   
  836.         T :in out Tree;          --| Tree value being stored in the tree.
  837.         V :in     Value_Type     --| The value being stored.
  838. ) is
  839. begin
  840.     if T /= null then 
  841.         T.Value := V;
  842.     else
  843.         raise Label_Not_Present;
  844.     end if;
  845. end Store_Value;
  846.  
  847. -----------------------------------------------------------------------------
  848. end Labeled_Trees;
  849. --::::::::::
  850. --set.bdy
  851. --::::::::::
  852. package body set_pkg is
  853.  
  854. --| Overview:
  855. --| See the package spec, private part, for the representation invariants
  856. --| and abstraction function for sets.  These define the implementation
  857. --| scheme.
  858.  
  859.  
  860.   -- Constructors:
  861.  
  862.     function create
  863.         return set is
  864.     begin
  865.         return set(list'(create));
  866.     end create;
  867.  
  868.     procedure insert(s: in out set;
  869.                      e: in     elem_type) is
  870.     begin
  871.     s := set(attach(e, list(s)));
  872.     end insert;
  873.  
  874.  
  875.     procedure delete(s: in out set;
  876.                      e: in     elem_type) is
  877.     begin
  878.     DeleteItems(list(s), e);
  879.     exception
  880.         when ItemNotPresent =>
  881.             null;
  882.     end delete;
  883.     
  884.     function intersect(s1, s2: set)
  885.     return set is
  886.     intersect_list: list := create;
  887.     iter: ListIter;
  888.     e: elem_type;
  889.     begin
  890.     iter := MakeListIter(list(s1));
  891.     while more(iter) loop
  892.         next(iter, e);
  893.         if IsInList(list(s2), e) then
  894.         intersect_list := attach(intersect_list, e);
  895.         end if;
  896.     end loop;
  897.     return set(intersect_list);
  898.     end intersect;
  899.  
  900.     function union(s1, s2: set)
  901.     return set is
  902.     union_list: list;
  903.     begin
  904.     return set(attach(copy(list(s1)), copy(list(s2))));
  905.     end union;
  906.  
  907.     function copy(s: set)
  908.     return set is
  909.     begin
  910.     return set(copy(list(s)));
  911.     end copy;
  912.   
  913.  
  914.   -- Query Operations:
  915.  
  916.     function equal(s1, s2: set)
  917.         return boolean is
  918.         iter: members_iter;
  919.         e: elem_type;
  920.     begin
  921.         -- s2 contains s1?
  922.         iter := make_members_iter(s1);
  923.         while more (iter) loop 
  924.             next(iter, e); 
  925.             if not is_member(s2, e) then return false; end if; 
  926.         end loop;
  927.  
  928.         -- s1 contains s2?
  929.         iter := make_members_iter(s2);
  930.         while more (iter) loop 
  931.             next(iter, e); 
  932.             if not is_member(s1, e) then return false; end if; 
  933.         end loop;
  934.  
  935.         -- s2 contains s1 and s1 contains s2 => equal(s1 = s2)
  936.         return true;
  937.     end equal;
  938.  
  939.     function is_empty(s: set)
  940.         return boolean is
  941.     begin
  942.     return IsEmpty(list(s));
  943.     end is_empty;
  944.  
  945.     function is_member(s: set;
  946.                        e: elem_type)
  947.         return boolean is
  948.     begin
  949.         return IsInList(list(s), e);
  950.     end is_member;
  951.  
  952.     function size(s: set)
  953.         return natural is
  954.     l: list := copy(list(s));
  955.     count: natural := 0;
  956.     begin
  957.     while not IsEmpty(l) loop
  958.         count := count + 1;
  959.         DeleteItems(l, FirstValue(l));
  960.     end loop;
  961.     return count;
  962.     end size;
  963.     
  964.  
  965.   -- Iterators:
  966.  
  967.     function make_members_iter(s: set)
  968.         return members_iter is
  969.     begin
  970.         return members_iter(copy(list(s)));
  971.     end make_members_iter;
  972.  
  973.     function more(iter: members_iter)
  974.         return boolean is
  975.     begin
  976.     return not IsEmpty(list(iter));
  977.     end more;
  978.     
  979.     procedure next(iter: in out members_iter;
  980.                    e:    out    elem_type) is
  981.         e2: elem_type;
  982.     begin
  983.         e := FirstValue(list(iter));
  984.         DeleteItems(list(iter), FirstValue(list(iter)));
  985.     exception
  986.         when EmptyList =>
  987.         raise no_more;
  988.     end next;
  989.  
  990.  
  991. -- Heap Management:
  992.  
  993.     procedure destroy(s: in out set) is
  994.     begin
  995.     destroy(list(s));
  996.     end destroy;
  997.  
  998. end set_pkg;
  999. --::::::::::
  1000. --stack.bdy
  1001. --::::::::::
  1002. -- $Source: /nosc/work/abstractions/stack/RCS/stack.bdy,v $
  1003. -- $Revision: 1.3 $ -- $Date: 85/02/01 10:19:36 $ -- $Author: ron $
  1004.  
  1005. -- $Source: /nosc/work/abstractions/stack/RCS/stack.bdy,v $
  1006. -- $Revision: 1.3 $ -- $Date: 85/02/01 10:19:36 $ -- $Author: ron $
  1007.  
  1008. with unchecked_deallocation;
  1009.  
  1010. package body stack_pkg is
  1011.  
  1012. --| Overview:
  1013. --| Implementation scheme is totally described by the statements of the
  1014. --| representation invariants and abstraction function that appears in
  1015. --| the package specification.  The implementation is so trivial that
  1016. --| further documentation is unnecessary.
  1017.  
  1018.     use elem_list_pkg;
  1019.     
  1020.     
  1021.   -- Constructors:
  1022.     
  1023.     function create
  1024.         return stack is
  1025.     begin
  1026.     return new stack_rec'(size => 0, elts => create);
  1027.     end create;
  1028.     
  1029.     procedure push(s: in out stack;
  1030.                    e: in     elem_type) is
  1031.     begin
  1032.         s.size := s.size + 1;
  1033.         s.elts := attach(e, s.elts);
  1034.     exception
  1035.         when constraint_error =>
  1036.             raise uninitialized_stack;
  1037.     end push;
  1038.  
  1039.     procedure pop(s: in out stack) is
  1040.     begin
  1041.         DeleteHead(s.elts);
  1042.         s.size := s.size - 1;
  1043.     exception
  1044.         when EmptyList =>
  1045.             raise empty_stack;
  1046.     when constraint_error =>
  1047.         raise uninitialized_stack;
  1048.     end pop;
  1049.  
  1050.     procedure pop(s: in out stack;
  1051.                   e: out    elem_type) is
  1052.     begin
  1053.         e := FirstValue(s.elts);
  1054.         DeleteHead(s.elts);
  1055.         s.size := s.size - 1;
  1056.     exception
  1057.         when EmptyList =>
  1058.             raise empty_stack;
  1059.     when constraint_error =>
  1060.         raise uninitialized_stack;
  1061.     end pop;
  1062.     
  1063.     function copy(s: stack)
  1064.         return stack is
  1065.     begin
  1066.     if s = null then raise uninitialized_stack; end if;
  1067.     
  1068.     return new stack_rec'(size => s.size,
  1069.                   elts => copy(s.elts));
  1070.     end;
  1071.  
  1072.     
  1073.   -- Queries:
  1074.  
  1075.     function top(s: stack)
  1076.         return elem_type is
  1077.     begin
  1078.         return FirstValue(s.elts);
  1079.     exception
  1080.         when EmptyList =>
  1081.         raise empty_stack;
  1082.     when constraint_error =>
  1083.         raise uninitialized_stack;
  1084.     end top;
  1085.  
  1086.     function size(s: stack)
  1087.         return natural is
  1088.     begin
  1089.         return s.size;
  1090.     exception
  1091.         when constraint_error =>
  1092.         raise uninitialized_stack;
  1093.     end size;
  1094.  
  1095.     function is_empty(s: stack)
  1096.         return boolean is
  1097.     begin
  1098.         return s.size = 0;
  1099.     exception
  1100.         when constraint_error =>
  1101.         raise uninitialized_stack;
  1102.     end is_empty;
  1103.  
  1104.  
  1105.   -- Heap Management:
  1106.     
  1107.     procedure destroy(s: in out stack) is
  1108.         procedure free_stack is
  1109.         new unchecked_deallocation(stack_rec, stack);
  1110.     begin
  1111.     destroy(s.elts);
  1112.     free_stack(s);
  1113.     exception
  1114.         when constraint_error =>    -- stack is null
  1115.             return; 
  1116.     end destroy;
  1117.    
  1118. end stack_pkg;
  1119. --::::::::::
  1120. --clp.bdy
  1121. --::::::::::
  1122. package FILE_LISTER is
  1123.    
  1124.    --------------------------------------------------------------------------
  1125.    --|BEGIN PROLOGUE
  1126.    --| DESCRIPTION            : FILE_LISTER is an abstract state machine which
  1127.    --|                        : manipulates a linked list of file names.
  1128.    --|                        : Through the ADD_FILE_NAME procedure, the
  1129.    --|                        : programmer can add one particular file name
  1130.    --|                        : to this list or a group of file names
  1131.    --|                        : specified by an include file (which is a file
  1132.    --|                        : that contains names of desired files and
  1133.    --|                        : other include files).
  1134.    --|                        : 
  1135.    --| REQUIREMENTS SUPPORTED : Object-Oriented Design of an Include File 
  1136.    --|                        : Processor
  1137.    --|                        : 
  1138.    --| LIMITATIONS            : None 
  1139.    --|                        : 
  1140.    --| AUTHOR(S)              : Richard Conn (RC)
  1141.    --|                        : 
  1142.    --| CHANGE LOG             : 02/24/88  RC  Initial Design with PDL
  1143.    --|                        : 02/24/88  RC  Code and Test
  1144.    --|                        : 
  1145.    --| REMARKS                : INCLUDE_FILE_PREFIX is brought out
  1146.    --|                        : in the front of the package FILE_LISTER
  1147.    --|                        : in order to ease portability to systems
  1148.    --|                        : other than the original target.
  1149.    --|                        : 
  1150.    --| PORTABILITY ISSUES     : Include file names are prefixed with the
  1151.    --|                        : character '@'; this is defined by the constant
  1152.    --|                        : INCLUDE_FILE_PREFIX.
  1153.    --|END PROLOGUE
  1154.    --------------------------------------------------------------------------
  1155.    
  1156.    INCLUDE_FILE_PREFIX : constant CHARACTER := '@';
  1157.    -- The INCLUDE_FILE_PREFIX is a character which preceeds the
  1158.    -- string passed to ADD_FILE_NAME when the characters following
  1159.    -- the INCLUDE_FILE_PREFIX comprise the name of an include file
  1160.    
  1161.    procedure ADD_FILE_NAME (FILE_NAME : in STRING);
  1162.    -- Add the indicated file or include file list to the end of
  1163.    -- the file list
  1164.    
  1165.    function GET_FILE_NAME return STRING;
  1166.    -- Return the next file name from the file list
  1167.    
  1168.    function IS_END return BOOLEAN;
  1169.    -- Indicate if the end of the file list has been reached
  1170.    
  1171.    procedure RESET;
  1172.    -- Reset the file list so the next file name is the first file
  1173.    -- in the list
  1174.    
  1175.    END_OF_FILE_LIST               : exception;
  1176.    FILE_LIST_NOT_FOUND            : exception;
  1177.    LINKED_LIST_ALLOCATION_PROBLEM : exception;
  1178.    UNEXPECTED_ERROR               : exception;
  1179.    
  1180. end FILE_LISTER;
  1181.  
  1182. with TEXT_IO;
  1183. package body FILE_LISTER is
  1184.    
  1185.    package LINKED_LIST is
  1186.       
  1187.       type FILE_NAME (FILE_NAME_LENGTH : NATURAL);
  1188.       type FILE_NAME_POINTER is access FILE_NAME;
  1189.       type FILE_NAME (FILE_NAME_LENGTH : NATURAL) is 
  1190.          record
  1191.             NAME : STRING (1 .. FILE_NAME_LENGTH);
  1192.             NEXT : FILE_NAME_POINTER;
  1193.          end record;
  1194.       
  1195.       FIRST_FILE   : FILE_NAME_POINTER := null;
  1196.       CURRENT_FILE : FILE_NAME_POINTER := null;
  1197.       LAST_FILE    : FILE_NAME_POINTER := null;
  1198.       
  1199.    end LINKED_LIST;
  1200.    
  1201.    function "=" (LEFT, RIGHT : in LINKED_LIST.FILE_NAME_POINTER) return BOOLEAN
  1202.        renames LINKED_LIST."=";
  1203.    -- The function provides a visible "=" operator for FILE_NAME_POINTER
  1204.    -- objects, eliminating the need to employ a USE clause
  1205.    
  1206.    procedure ADD_FILE_NAME (FILE_NAME : in STRING) is
  1207.       
  1208.       --============================= PDL ==================================
  1209.       --|ABSTRACT:
  1210.       --|    ADD_FILE_NAME adds the named file to the file list, building
  1211.       --|    onto a linked-list.  If FILE_NAME is an include file,
  1212.       --|    all files named by this include file and the include files
  1213.       --|    it references are added to the list.
  1214.       --|
  1215.       --|DESIGN DESCRIPTION:
  1216.       --|    If the first character is not the INCLUDE_FILE_PREFIX,
  1217.       --|      add the file name to the list
  1218.       --|    Else
  1219.       --|        Open FILE_NAME; if exception, raise FILE_LIST_NOT_FOUND
  1220.       --|        Loop until end of file of FILE_NAME:
  1221.       --|            Get next line from include file
  1222.       --|            Case next line
  1223.       --|                When blank or comment, do nothing
  1224.       --|                When include file name, Call ADD_FILE_NAME (recurse)
  1225.       --|                When file name, add file name to linked list
  1226.       --|            End case
  1227.       --|        End loop
  1228.       --|    End if
  1229.       --| 
  1230.       --====================================================================
  1231.       
  1232.       FD : TEXT_IO.FILE_TYPE;
  1233.       type INLINE is 
  1234.          record
  1235.             CONTENT : STRING (1 .. 400);
  1236.             LAST    : NATURAL;
  1237.          end record;
  1238.       FILE : INLINE;
  1239.       
  1240.       procedure ADD_NAME_TO_LIST (FILE_NAME : in STRING) is
  1241.          TEMP : LINKED_LIST.FILE_NAME_POINTER;
  1242.       begin
  1243.          if LINKED_LIST.FIRST_FILE = null then
  1244.             begin
  1245.                LINKED_LIST.FIRST_FILE := 
  1246.                   new LINKED_LIST.FILE_NAME (FILE_NAME'LENGTH);
  1247.             exception
  1248.                when others     =>
  1249.                   raise LINKED_LIST_ALLOCATION_PROBLEM;
  1250.             end;
  1251.             LINKED_LIST.FIRST_FILE.NAME (1 .. FILE_NAME'LENGTH) := FILE_NAME;
  1252.             LINKED_LIST.LAST_FILE := LINKED_LIST.FIRST_FILE;
  1253.             LINKED_LIST.CURRENT_FILE := LINKED_LIST.FIRST_FILE;
  1254.          else
  1255.             begin
  1256.                TEMP := new LINKED_LIST.FILE_NAME (FILE_NAME'LENGTH);
  1257.             exception
  1258.                when others     =>
  1259.                   raise LINKED_LIST_ALLOCATION_PROBLEM;
  1260.             end;
  1261.             LINKED_LIST.LAST_FILE.NEXT        := TEMP;
  1262.             TEMP.NAME (1 .. FILE_NAME'LENGTH) := FILE_NAME;
  1263.             LINKED_LIST.LAST_FILE             := TEMP;
  1264.          end if;
  1265.       end ADD_NAME_TO_LIST;
  1266.       
  1267.    begin
  1268.       if FILE_NAME (FILE_NAME'FIRST) /= INCLUDE_FILE_PREFIX then
  1269.          ADD_NAME_TO_LIST (FILE_NAME);
  1270.       else
  1271.          begin
  1272.             TEXT_IO.OPEN (FD, TEXT_IO.IN_FILE, 
  1273.                           FILE_NAME (FILE_NAME'FIRST + 1 .. FILE_NAME'LAST));
  1274.          exception
  1275.             when others   =>
  1276.                raise FILE_LIST_NOT_FOUND;
  1277.          end;
  1278.          
  1279.          -- Loop through file
  1280.          while not TEXT_IO.END_OF_FILE (FD) loop
  1281.             TEXT_IO.GET_LINE (FD, FILE.CONTENT, FILE.LAST);
  1282.             if FILE.LAST > 0 then
  1283.                if FILE.CONTENT (1) /= '-' then
  1284.                   if FILE.CONTENT (1) = INCLUDE_FILE_PREFIX then
  1285.                      ADD_FILE_NAME (FILE.CONTENT (1 .. FILE.LAST));
  1286.                   else
  1287.                      ADD_NAME_TO_LIST (FILE.CONTENT (1 .. FILE.LAST));
  1288.                   end if;
  1289.                end if;
  1290.             end if;
  1291.          end loop;
  1292.          
  1293.          TEXT_IO.CLOSE (FD);
  1294.          
  1295.       end if;
  1296.       
  1297.    exception
  1298.       when FILE_LIST_NOT_FOUND | LINKED_LIST_ALLOCATION_PROBLEM   =>
  1299.          raise ;
  1300.       when others    =>
  1301.          raise UNEXPECTED_ERROR;
  1302.    end ADD_FILE_NAME;
  1303.    
  1304.    function GET_FILE_NAME return STRING is
  1305.       
  1306.       --============================= PDL ==================================
  1307.       --|ABSTRACT:
  1308.       --|    GET_FILE_NAME returns the next file name from the include
  1309.       --|    file.
  1310.       --| 
  1311.       --|DESIGN DESCRIPTION:
  1312.       --|    Check to see if LINKED_LIST.CURRENT_FILE is null and raise
  1313.       --|      END_OF_FILE_LIST if so
  1314.       --|    Set TEMP to point to LINKED_LIST.CURRENT_FILE
  1315.       --|    If LINKED_LIST.CURRENT_FILE = LINKED_LIST.LAST_FILE then
  1316.       --|        Set LINKED_LIST.LAST_FILE to null
  1317.       --|    Else
  1318.       --|        Set LINKED_LIST.CURRENT_FILE to LINKED_LIST.CURRENT_FILE.NEXT
  1319.       --|    End if
  1320.       --|    Return TEMP.NAME
  1321.       --====================================================================
  1322.       
  1323.       TEMP : LINKED_LIST.FILE_NAME_POINTER;
  1324.       
  1325.    begin
  1326.       if IS_END then
  1327.          raise END_OF_FILE_LIST;
  1328.       end if;
  1329.       TEMP := LINKED_LIST.CURRENT_FILE;
  1330.       if LINKED_LIST.CURRENT_FILE = LINKED_LIST.LAST_FILE then
  1331.          LINKED_LIST.CURRENT_FILE := null;
  1332.       else
  1333.          LINKED_LIST.CURRENT_FILE := LINKED_LIST.CURRENT_FILE.NEXT;
  1334.       end if;
  1335.       return TEMP.NAME;
  1336.    exception
  1337.       when END_OF_FILE_LIST    =>
  1338.          raise ;
  1339.       when others    =>
  1340.          raise UNEXPECTED_ERROR;
  1341.    end GET_FILE_NAME;
  1342.    
  1343.    function IS_END return BOOLEAN is
  1344.       
  1345.       --============================= PDL ==================================
  1346.       --|ABSTRACT:
  1347.       --|   END_OF_FILE indicates when the end of the include file
  1348.       --|   (actually, linked list) is encountered.
  1349.       --|
  1350.       --|DESIGN DESCRIPTION:
  1351.       --|   Return TRUE if LINKED_LIST.CURRENT_FILE is null; FALSE otherwise
  1352.       --====================================================================
  1353.       
  1354.    begin
  1355.       return LINKED_LIST.CURRENT_FILE = null;
  1356.    end IS_END;
  1357.    
  1358.    procedure RESET is
  1359.       
  1360.       --============================= PDL ==================================
  1361.       --|ABSTRACT:
  1362.       --|   RESET resets the FILE_LISTER package for reprocessing
  1363.       --|   the current file list.
  1364.       --|
  1365.       --|DESIGN DESCRIPTION:
  1366.       --|   Set LINKED_LIST.CURRENT_FILE to null
  1367.       --====================================================================
  1368.       
  1369.    begin
  1370.       LINKED_LIST.CURRENT_FILE := LINKED_LIST.FIRST_FILE;
  1371.    end RESET;
  1372.    
  1373. end FILE_LISTER;
  1374. -- **********************************************
  1375. -- *                                            *
  1376. -- * COMMAND_LINE_PROCESSOR                     * BODY
  1377. -- *                                            *
  1378. -- **********************************************
  1379. with CLI;          -- from CLI2.SRC
  1380. with FILE_LISTER;  -- from FLISTER.SRC
  1381. package body COMMAND_LINE_PROCESSOR is
  1382.  
  1383.     NUMBER_OF_FILE_NAME_TOKENS : NATURAL;
  1384.     INIT_DONE : BOOLEAN := FALSE;
  1385.     OUTPUT_FILE_EXISTS : BOOLEAN := FALSE;
  1386.  
  1387.     -- ..............................................
  1388.     -- .                                            .
  1389.     -- . INITIALIZE                                 . BODY
  1390.     -- .                                            .
  1391.     -- ..............................................
  1392.     procedure INITIALIZE (PROGRAM_NAME : in STRING;
  1393.                           COMMAND_KIND : in COMMAND_LINE_LAYOUT
  1394.                                          := ONE_OUTPUT_FILE) is
  1395.     begin
  1396.         if COMMAND_KIND = ONE_OUTPUT_FILE then
  1397.             CLI.INITIALIZE(PROGRAM_NAME,
  1398.                        "Enter input file names and output file name: ");
  1399.             NUMBER_OF_FILE_NAME_TOKENS := CLI.ARGC - 1;
  1400.             for I in 1 .. NUMBER_OF_FILE_NAME_TOKENS - 1 loop
  1401.                 FILE_LISTER.ADD_FILE_NAME(CLI.ARGV(I));
  1402.             end loop;
  1403.             OUTPUT_FILE_EXISTS := TRUE;
  1404.         else
  1405.             CLI.INITIALIZE(PROGRAM_NAME,
  1406.                        "Enter input file names: ");
  1407.             NUMBER_OF_FILE_NAME_TOKENS := CLI.ARGC - 1;
  1408.             for I in 1 .. NUMBER_OF_FILE_NAME_TOKENS loop
  1409.                 FILE_LISTER.ADD_FILE_NAME(CLI.ARGV(I));
  1410.             end loop;
  1411.             OUTPUT_FILE_EXISTS := FALSE;
  1412.         end if;
  1413.         INIT_DONE := TRUE;
  1414.     exception
  1415.         when FILE_LISTER.LINKED_LIST_ALLOCATION_PROBLEM =>
  1416.                        raise ALLOCATION_PROBLEM;
  1417.         when others => raise UNEXPECTED_ERROR;
  1418.     end INITIALIZE;
  1419.  
  1420.     -- ..............................................
  1421.     -- .                                            .
  1422.     -- . RESET                                      . BODY
  1423.     -- .                                            .
  1424.     -- ..............................................
  1425.     procedure RESET is
  1426.     begin
  1427.         if not INIT_DONE then
  1428.             raise INIT_ERROR;
  1429.         else
  1430.             FILE_LISTER.RESET;
  1431.         end if;
  1432.     exception
  1433.         when INIT_ERROR => raise;
  1434.         when others     => raise UNEXPECTED_ERROR;
  1435.     end RESET;
  1436.  
  1437.     -- ..............................................
  1438.     -- .                                            .
  1439.     -- . IS_END                                     . BODY
  1440.     -- .                                            .
  1441.     -- ..............................................
  1442.     function IS_END return BOOLEAN is
  1443.     begin
  1444.         if not INIT_DONE then
  1445.             raise INIT_ERROR;
  1446.         else
  1447.             return FILE_LISTER.IS_END;
  1448.         end if;
  1449.     exception
  1450.         when INIT_ERROR => raise;
  1451.         when others     => raise UNEXPECTED_ERROR;
  1452.     end IS_END;
  1453.  
  1454.     -- ..............................................
  1455.     -- .                                            .
  1456.     -- . FILE_NAME                                  . BODY
  1457.     -- .                                            .
  1458.     -- ..............................................
  1459.     function FILE_NAME return STRING is
  1460.     begin
  1461.         if not INIT_DONE then
  1462.             raise INIT_ERROR;
  1463.         else
  1464.             return FILE_LISTER.GET_FILE_NAME;
  1465.         end if;
  1466.     exception
  1467.         when INIT_ERROR => raise;
  1468.         when FILE_LISTER.END_OF_FILE_LIST =>
  1469.                            raise END_OF_FILE_LIST;
  1470.         when others     => raise UNEXPECTED_ERROR;
  1471.     end FILE_NAME;
  1472.  
  1473.     -- ..............................................
  1474.     -- .                                            .
  1475.     -- . OUTPUT_FILE_NAME                           . BODY
  1476.     -- .                                            .
  1477.     -- ..............................................
  1478.     function OUTPUT_FILE_NAME return STRING is
  1479.     begin
  1480.         if not INIT_DONE then
  1481.             raise INIT_ERROR;
  1482.         else
  1483.             if OUTPUT_FILE_EXISTS then
  1484.                 return CLI.ARGV(NUMBER_OF_FILE_NAME_TOKENS);
  1485.             else
  1486.                 return "";
  1487.             end if;
  1488.         end if;
  1489.     exception
  1490.         when INIT_ERROR => raise;
  1491.         when others     => raise UNEXPECTED_ERROR;
  1492.     end OUTPUT_FILE_NAME;
  1493.  
  1494.     -- ..............................................
  1495.     -- .                                            .
  1496.     -- . FILE_NAME_COUNT                            . BODY
  1497.     -- .                                            .
  1498.     -- ..............................................
  1499.     function FILE_NAME_COUNT return NATURAL is
  1500.     begin
  1501.         if not INIT_DONE then
  1502.             raise INIT_ERROR;
  1503.         else
  1504.             return NUMBER_OF_FILE_NAME_TOKENS;
  1505.         end if;
  1506.     exception
  1507.         when INIT_ERROR => raise;
  1508.         when others     => raise UNEXPECTED_ERROR;
  1509.     end FILE_NAME_COUNT;
  1510.  
  1511. end COMMAND_LINE_PROCESSOR;
  1512. --::::::::::
  1513. --lbintree.bdy
  1514. --::::::::::
  1515. package body labeled_binary_trees_pkg is
  1516. --| Efficient implementation of labeled binary trees.
  1517.  
  1518. --| OVERVIEW
  1519.  
  1520. --| Implemented using Binary_Trees_Pkg.
  1521.  
  1522. ----------------------------------------------------------------------------
  1523.                 -- Implementation --
  1524. ----------------------------------------------------------------------------
  1525. -- For the pseudo-private part
  1526.  
  1527. function LV_Differ(P, Q: Label_Value_Pair) return integer is
  1528. begin
  1529.     return Difference(P.Label, Q.Label);
  1530.  
  1531. end LV_Differ;
  1532.  
  1533. ----------------------------------------------------------------------------
  1534.  
  1535. Procedure Insert(    --| Insert a label/value into a tree.
  1536.     L: Label_Type;    --| Label to be associated with a value
  1537.     V: Value_Type;    --| Value to be inserted
  1538.     T: Tree        --| Tree to contain the new value
  1539.     ) is
  1540.  
  1541. begin
  1542.     LVT.Insert(Label_Value_Pair'(L, V), T);
  1543.  
  1544. end Insert;
  1545.  
  1546. ----------------------------------------------------------------------------
  1547.  
  1548. Procedure Insert_if_not_Found(
  1549. --| Insert a value into a tree, provided a duplicate value is not already there
  1550.     L: Label_Type;    --| Label to look for
  1551.     V: Value_Type;    --| Value to be inserted
  1552.     T: Tree;        --| Tree to contain the new value
  1553.     Found: out boolean;
  1554.     Duplicate: out Value_Type
  1555.     ) --| Raises: Invalid_Tree.
  1556. is
  1557.     was_Found: boolean;
  1558.     Match: Label_Value_Pair;
  1559.  
  1560. begin
  1561.     LVT.Insert_If_Not_Found(Label_Value_Pair'(L, V), T, was_Found, Match);
  1562.     Found := was_Found;
  1563.     if was_Found then
  1564.     Duplicate := Match.Value;
  1565.     end if;
  1566.  
  1567. end Insert_if_Not_Found;
  1568.  
  1569. ----------------------------------------------------------------------------
  1570.  
  1571. procedure Replace_if_Found(
  1572. --| Replace a value if label exists, otherwise insert it.
  1573.     L: Label_Type;    --| Label to look for
  1574.     V: Value_Type;    --| Value to be inserted
  1575.     T: Tree;        --| Tree to contain the new value
  1576.     Found: out boolean;    --| Becomes True iff L already in tree
  1577.     Old_Value: out Value_Type    --| the duplicate value, if there is one
  1578.     ) --| Raises: Invalid_Tree.
  1579. is
  1580.     was_Found: boolean;
  1581.     Match: Label_Value_Pair;
  1582.  
  1583. begin
  1584.     LVT.Replace_if_Found(Label_Value_Pair'(L, V), T, was_Found, Match);
  1585.     Found := was_Found;
  1586.     if was_Found then
  1587.     Old_Value := Match.Value;
  1588.     end if;
  1589.  
  1590. end Replace_if_Found;
  1591.  
  1592. ----------------------------------------------------------------------------
  1593.  
  1594. procedure Destroy_Deep(    --| Free all space allocated to a tree.
  1595.     T: in out Tree    --| The tree to be reclaimed.
  1596.     ) is
  1597.  
  1598.     procedure Destroy_Pair(P: in out Label_Value_Pair) is
  1599.     begin
  1600.     free_Value(P.Value);
  1601.     free_Label(P.Label);
  1602.  
  1603.     end Destroy_Pair;
  1604.  
  1605.     procedure LV_Destroy_Deep is new LVT.Destroy_Deep(Destroy_Pair);
  1606.  
  1607. begin
  1608.     LV_Destroy_Deep(T);
  1609.  
  1610. end Destroy_Deep;
  1611.  
  1612. ----------------------------------------------------------------------------
  1613.  
  1614. function Balanced_Tree(    
  1615.     Count: natural
  1616.     ) return Tree
  1617. is
  1618.     function Next return Label_Value_Pair is
  1619.     L: Label_Type;
  1620.     V: Value_Type;
  1621.     begin
  1622.     Next_Pair(L, V);    -- this is provided with instantiation
  1623.     return Label_Value_Pair'(L, V);
  1624.  
  1625.     end Next;
  1626.  
  1627.     function LV_Balanced_Tree is new LVT.Balanced_Tree(Next);
  1628.  
  1629. begin
  1630.     return LV_Balanced_Tree(Count);
  1631.  
  1632. end Balanced_Tree;
  1633.  
  1634. ----------------------------------------------------------------------------
  1635.  
  1636. function Copy_Tree(
  1637.     T: Tree
  1638.     ) return Tree
  1639. is
  1640.     function Copy_Pair(P: Label_Value_Pair) return Label_Value_Pair is
  1641.     begin
  1642.     return Label_Value_Pair'(copy_Label(P.Label), copy_Value(P.Value));
  1643.  
  1644.     end Copy_Pair;
  1645.  
  1646.     function LV_Copy_Tree is new LVT.Copy_Tree(Copy_Pair);
  1647.  
  1648. begin
  1649.     return LV_Copy_Tree(T);
  1650.  
  1651. end Copy_Tree;
  1652.  
  1653. ----------------------------------------------------------------------------
  1654.  
  1655. Function Find(        --| Search a tree for a value.
  1656.     L: Label_Type;    --| Label to be located
  1657.     T: Tree        --| Tree to be searched
  1658.     ) return Value_Type --| Raises: Not_Found, Invalid_Tree.
  1659. is
  1660.     P: Label_Value_Pair;
  1661.  
  1662. begin
  1663.     P.Label := L;
  1664.     P := LVT.Find(P, T);
  1665.     return P.Value;
  1666.  
  1667. end Find;
  1668.  
  1669.  
  1670. Procedure Find(            --| Search a tree for a value.
  1671.     L: Label_Type;        --| Label to be located
  1672.     T: Tree;            --| Tree to be searched
  1673.     Found: out Boolean;        --| TRUE iff a match was found
  1674.     Match: out Value_Type    --| Matching value found in the tree
  1675.     ) --| Raises: Invalid_Tree;
  1676.  
  1677. is
  1678.     P: Label_Value_Pair;
  1679.     was_Found: boolean;
  1680.  
  1681. begin
  1682.     P.Label := L;
  1683.     LVT.Find(P, T, was_Found, P);
  1684.     Found := was_Found;
  1685.     if was_Found then
  1686.       Match := P.Value;
  1687.     end if;
  1688.  
  1689. end Find;
  1690.  
  1691. ----------------------------------------------------------------------------
  1692.  
  1693. function is_Found(    --| Check a tree for a value.
  1694.     L: Label_Type;    --| Label to be located
  1695.     T: Tree        --| Tree to be searched
  1696.     ) return Boolean    --| Raises: Invalid_Tree;
  1697. is
  1698.     P: Label_Value_Pair;
  1699.     Found: Boolean;
  1700.  
  1701. begin
  1702.     P.Label := L;
  1703.     LVT.Find(P, T, Found, P);
  1704.     return Found;
  1705.  
  1706. end is_Found;
  1707.  
  1708.  
  1709. --| Effects: Return TRUE iff L is found in T.
  1710.  
  1711. ----------------------------------------------------------------------------
  1712.  
  1713. procedure Visit(
  1714.     T: Tree;
  1715.     Order: Scan_Kind
  1716.     )
  1717. is
  1718.     procedure Process_Pair(P: Label_Value_Pair) is
  1719.     begin
  1720.     Process(P.Label, P.Value);
  1721.  
  1722.     end Process_Pair;
  1723.  
  1724.     procedure LV_Visit is new LVT.Visit(Process_Pair);
  1725.  
  1726. begin
  1727.     LV_Visit(T, Order);
  1728.  
  1729. end Visit;
  1730.  
  1731.  
  1732. --| Effects: Invoke Process(V) for each value V in T.  The nodes are visited
  1733. --| in the order specified by Order.  Although more limited than using
  1734. --| an iterator, this function is also much faster.
  1735.  
  1736. ----------------------------------------------------------------------------
  1737.  
  1738. procedure Next(        --| Scan the next value in I
  1739.     I: in out Iterator;    --| an active iterator
  1740.     L: out Label_Type;    --| Next label scanned
  1741.     V: out Value_Type    --| Next value scanned
  1742.     )
  1743. is
  1744.     P: Label_Value_Pair;
  1745.  
  1746. begin
  1747.     LVT.Next(I, P);
  1748.     L := P.Label;
  1749.     V := P.Value;
  1750.  
  1751. end Next;
  1752.  
  1753. ----------------------------------------------------------------------------
  1754.  
  1755.  
  1756. end labeled_binary_trees_pkg;
  1757. --::::::::::
  1758. --ordset.bdy
  1759. --::::::::::
  1760. package body OrderedSets is
  1761. -------------------------------------------------------------------------------
  1762. --                Local Subprograms
  1763. -------------------------------------------------------------------------------
  1764.  
  1765. -------------------------------------------------------------------------------
  1766.  
  1767. function "<" (     --| Implements "<" for the type member.
  1768.          X :in   Member;
  1769.          Y :in   Member 
  1770. ) return boolean is
  1771.  
  1772. begin
  1773.      return X.Info < Y.Info;
  1774. end;
  1775.  
  1776. -------------------------------------------------------------------------------
  1777.  
  1778.  
  1779. -------------------------------------------------------------------------------
  1780. --               Visible Subprograms
  1781. -------------------------------------------------------------------------------
  1782.  
  1783.  
  1784. -------------------------------------------------------------------------------
  1785.  
  1786. function Cardinality ( 
  1787.               S :in Set  --| The set whose size is being computed.
  1788. ) return natural is
  1789.  
  1790.     T        :TreePkg.TreeIter;
  1791.     M        :Member;
  1792.     count    :natural := 0;
  1793. begin
  1794.     T := TreePkg.MakeTreeIter (S.SetRep);
  1795.     while TreePkg.More (T) loop
  1796.         TreePkg.Next (T, M);
  1797.         count := count + 1;
  1798.     end loop;
  1799.     return count;
  1800. end Cardinality;            
  1801.  
  1802. -------------------------------------------------------------------------------
  1803.  
  1804. function Create
  1805.  
  1806. return Set is
  1807.     S :Set;
  1808. begin
  1809.     S.SetRep := TreePkg.Create;
  1810.     return S;
  1811. end Create;
  1812.  
  1813. ------------------------------------------------------------------------------
  1814.  
  1815. procedure Destroy ( 
  1816.          S :in out Set
  1817. ) is
  1818.  
  1819. begin
  1820.     TreePkg.DestroyTree (S.SetRep);
  1821. end Destroy;
  1822.  
  1823. -----------------------------------------------------------------------------
  1824.  
  1825. function GetCount (
  1826.          I :in    SetIter
  1827. ) return natural is
  1828.  
  1829. begin
  1830.      return I.Count;
  1831. end;
  1832.  
  1833. -----------------------------------------------------------------------------
  1834. procedure Insert(
  1835.           M :in     ItemType;
  1836.           S :in out Set
  1837. ) is
  1838.     Subtree       :TreePkg.Tree;
  1839.     Exists        :boolean;
  1840.     MemberToEnter :Member := ( Info => M, count => 1);
  1841. begin
  1842.     --| If NewMember doesn't exist in SetRep it is added.  If it does exist
  1843.     --| Exists comes back true and then M's count is updated.  Since the
  1844.     --| first argument of TreePkg.Insert is in out, after Insert 
  1845.     --| MemberToEnter has the value stored in the tree.  Thus if we
  1846.     --| need to update the count we can simple bump the count in MemberToEnter.
  1847.  
  1848.     TreePkg.InsertNode (MemberToEnter, S.SetRep, SubTree, Exists);    
  1849.     if Exists then 
  1850.         MemberToEnter.Count := MemberToEnter.Count + 1;
  1851.         TreePkg.Deposit (MemberToEnter, SubTree);
  1852.     end if;        
  1853. end Insert;
  1854.  
  1855. ------------------------------------------------------------------------------
  1856.  
  1857. function MakeSetIter (   
  1858.          S :in Set
  1859. )        return SetIter is
  1860.  
  1861.     I :SetIter;
  1862. begin
  1863.     I.Place := TreePkg.MakeTreeIter (S.SetRep);
  1864.     I.Count := 0;
  1865.     return I;
  1866. end;
  1867.  
  1868.  ------------------------------------------------------------------------------
  1869.  
  1870. function More ( 
  1871.           I :in     SetIter
  1872. )         return boolean is
  1873.  
  1874. begin
  1875.     return TreePkg.More (I.Place);
  1876. end;
  1877.     
  1878. ------------------------------------------------------------------------------
  1879.  
  1880. procedure Next (
  1881.          I :in out SetIter;
  1882.          M :   out ItemType
  1883. ) is
  1884.     TempMember :Member;
  1885. begin
  1886.     TreePkg.Next (I.Place, TempMember);
  1887.     M := TempMember.Info;
  1888.     I.Count := TempMember.Count;
  1889. end;
  1890.  
  1891. ------------------------------------------------------------------------------
  1892.  
  1893. end OrderedSets;
  1894. --::::::::::
  1895. --string.bdy
  1896. --::::::::::
  1897. -- $Source: /nosc/work/abstractions/string/RCS/string.bdy,v $
  1898. -- $Revision: 1.3 $ -- $Date: 85/02/01 10:58:51 $ -- $Author: ron $
  1899.  
  1900. -- $Source: /nosc/work/abstractions/string/RCS/string.bdy,v $
  1901. -- $Revision: 1.3 $ -- $Date: 85/02/01 10:58:51 $ -- $Author: ron $
  1902.  
  1903. with unchecked_deallocation;
  1904. with lists, stack_pkg;
  1905. with case_insensitive_string_comparison;
  1906.  
  1907. package body string_pkg is
  1908.  
  1909. --| Overview:
  1910. --| The implementation for most operations is fairly straightforward.
  1911. --| The interesting aspects involve the allocation and deallocation of
  1912. --| heap space.  This is done as follows:
  1913. --|
  1914. --|     1. A stack of accesses to lists of string_type values is set up
  1915. --|        so that the top of the stack always refers to a list of values
  1916. --|        that were allocated since the last invocation of mark.
  1917. --|        The stack is called scopes, referring to the dynamic scopes
  1918. --|        defined by the invocations of mark and release.
  1919. --|        There is an implicit invocation of mark when the
  1920. --|        package body is elaborated; this is implemented with an explicit 
  1921. --|        invocation in the package initialization code.
  1922. --|
  1923. --|     2. At each invocation of mark, a pointer to an empty list
  1924. --|        is pushed onto the stack.
  1925. --|
  1926. --|     3. At each invocation of release, all of the values in the
  1927. --|        list referred to by the pointer at the top of the stack are
  1928. --|        returned to the heap.  Then the list, and the pointer to it,
  1929. --|        are returned to the heap.  Finally, the stack is popped.
  1930.  
  1931.     package CISC renames case_insensitive_string_comparison;
  1932.  
  1933.     package string_list_pkg is new lists(string_type);
  1934.     subtype string_list is string_list_pkg.list;
  1935.  
  1936.     type string_list_ptr is access string_list;
  1937.  
  1938.     package scope_stack_pkg is new stack_pkg(string_list_ptr);
  1939.     subtype scope_stack is scope_stack_pkg.stack;
  1940.  
  1941.     use string_list_pkg;
  1942.     use scope_stack_pkg;
  1943.  
  1944.     scopes: scope_stack;     -- See package body overview.
  1945.  
  1946.     current_comparison_option: comparison_option := case_sensitive;
  1947.  
  1948.     -- Utility functions/procedures:
  1949.  
  1950.     function enter(s: in string_type)
  1951.         return string_type;
  1952.  
  1953.       --| Raises: illegal_alloc
  1954.       --| Effects:
  1955.       --| Stores s, the address of s.all, in current scope list (top(scopes)),
  1956.       --| and returns s.  Useful for functions that create and return new
  1957.       --| string_type values.
  1958.       --| Raises illegal_alloc if the scopes stack is empty.
  1959.  
  1960.     function string_lower(s: in string)
  1961.     return string;
  1962.  
  1963.       --| Effects:
  1964.       --| Return a string with the same bounds and contents as s, with the
  1965.       --| exception that all upper case characters are replaced with their
  1966.       --| lower case counterparts.
  1967.  
  1968.     function string_upper(s: in string)
  1969.     return string;
  1970.  
  1971.       --| Effects:
  1972.       --| Return a string with the same bounds and contents as s, with the
  1973.       --| exception that all lower case characters are replaced with their
  1974.       --| upper case counterparts.
  1975.  
  1976.     function string_equal(s1, s2: in string)
  1977.     return boolean;
  1978.  
  1979.       --| Effects: 
  1980.       --| If current_comparison_option = case_sensitive, then return 
  1981.       --| (s1 = s2); otherwise, return string_lower(s1) = string_lower(s2).
  1982.  
  1983.     function string_less(s1, s2: in string)
  1984.     return boolean;
  1985.  
  1986.       --| Effects: 
  1987.       --| If current_comparison_option = case_sensitive, then return 
  1988.       --| (s1 < s2); otherwise, return string_lower(s1) < string_lower(s2).
  1989.  
  1990.     function string_less_or_equal(s1, s2: in string)
  1991.     return boolean; 
  1992.  
  1993.       --| Effects: 
  1994.       --| If current_comparison_option = case_sensitive, then return 
  1995.       --| (s1 <= s2); otherwise, return string_lower(s1) <= string_lower(s2).
  1996.  
  1997.     function match_string(s1, s2: in string; start: in positive := 1)
  1998.         return natural;
  1999.  
  2000.       --| Raises: no_match
  2001.       --| Effects:
  2002.       --| Returns the minimum index, i, in s1'range such that
  2003.       --| s1(i..i + s2'length - 1) = s2.  Returns 0 if no such index.
  2004.       --| Requires:
  2005.       --| s1'first = 1.
  2006.  
  2007. -- Constructors:
  2008.  
  2009.     function create(s: in string)
  2010.         return string_type is
  2011.         subtype constr_str is string(1..s'length);
  2012.         dec_s: constr_str := s;
  2013.     begin
  2014.           return enter(new constr_str'(dec_s));
  2015.     end create;
  2016.  
  2017.  
  2018.     function "&"(s1, s2: in string_type)
  2019.         return string_type is
  2020.     begin
  2021.     if is_empty(s1) then return enter(make_persistent(s2)); end if;
  2022.     if is_empty(s2) then return enter(make_persistent(s1)); end if; 
  2023.         return create(s1.all & s2.all);
  2024.     end "&";
  2025.  
  2026.     function "&"(s1: in string_type; s2: in string)
  2027.         return string_type is
  2028.     begin
  2029.     if s1 = null then return create(s2); end if; 
  2030.     return create(s1.all & s2); 
  2031.     end "&";
  2032.  
  2033.     function "&"(s1: in string; s2: in string_type)
  2034.         return string_type is
  2035.     begin
  2036.     if s2 = null then return create(s1); end if; 
  2037.     return create(s1 & s2.all); 
  2038.     end "&";
  2039.     
  2040.     function substr(s: in string_type; i: in positive; len: in natural)
  2041.         return string_type is
  2042.     begin
  2043.         if len = 0 then return null; end if; 
  2044.         return create(s(i..(i + len - 1)));
  2045.     exception
  2046.     when constraint_error =>      -- on array fetch or null deref
  2047.         raise bounds;
  2048.     end substr;
  2049.  
  2050.     function splice(s: in string_type; i: in positive; len: in natural)
  2051.         return string_type is
  2052.     begin
  2053.         if len = 0 then return enter(make_persistent(s)); end if;
  2054.         if i + len - 1 > length(s) then raise bounds; end if; 
  2055.  
  2056.         return create(s(1..(i - 1)) & s((i + len)..length(s)));
  2057.     end splice;
  2058.  
  2059.     function insert(s1, s2: in string_type; i: in positive)
  2060.         return string_type is
  2061.     begin
  2062.         if i > length(s1) + 1 then raise bounds; end if;
  2063.  
  2064.     if s1 = null then return create(value(s2)); end if;
  2065.     if s2 = null then return create(s1.all); end if;
  2066.  
  2067.         return create(s1(1..(i - 1)) & s2.all & s1(i..s1'last));
  2068.     end insert;
  2069.  
  2070.     function insert(s1: in string_type; s2: in string; i: in positive)
  2071.         return string_type is
  2072.     begin
  2073.         if i > length(s1) + 1 then raise bounds; end if;
  2074.     if s1 = null then return create(s2); end if;
  2075.  
  2076.         return create(s1(1..(i - 1)) & s2 & s1(i..s1'last));
  2077.     end insert;
  2078.  
  2079.     function insert(s1: in string; s2: in string_type; i: in positive)
  2080.         return string_type is
  2081.     begin
  2082.     if i not in s1'first..s1'last + 1 then raise bounds; end if;
  2083.     if s2 = null then return create(s1); end if; 
  2084.  
  2085.         return create(s1(s1'first..(i - 1)) & s2.all & s1(i..s1'last));
  2086.     end insert;
  2087.  
  2088.     function lower(s: in string)
  2089.     return string_type is  
  2090.     begin
  2091.     return create(string_lower(s));
  2092.     end lower;
  2093.  
  2094.     function lower(s: in string_type)
  2095.     return string_type is
  2096.     begin
  2097.     if s = null then return null; end if; 
  2098.     return create(string_lower(s.all));
  2099.     end lower;
  2100.  
  2101.     function upper(s: in string)
  2102.     return string_type is
  2103.     begin
  2104.     return create(string_upper(s));
  2105.     end upper;
  2106.  
  2107.     function upper(s: in string_type)
  2108.     return string_type is
  2109.     begin
  2110.     if s = null then return null; end if; 
  2111.     return create(string_upper(s.all));
  2112.     end upper;
  2113.       
  2114.     
  2115. -- Heap Management:
  2116.  
  2117.     function make_persistent(s: in string_type)
  2118.     return string_type is
  2119.         subtype constr_str is string(1..length(s));
  2120.     begin
  2121.         if s = null or else s.all = "" then return null;
  2122.         else return new constr_str'(s.all);
  2123.         end if; 
  2124.     end make_persistent; 
  2125.     
  2126.     function make_persistent(s: in string)
  2127.     return string_type is
  2128.         subtype constr_str is string(1..s'length);
  2129.         dec_s: constr_str := s;
  2130.     begin
  2131.     if dec_s = "" then return null; 
  2132.         else return new constr_str'(dec_s); end if; 
  2133.     end make_persistent; 
  2134.  
  2135.     procedure real_flush is new unchecked_deallocation(string,
  2136.                                                        string_type);
  2137.       --| Effect:
  2138.       --| Return space used by argument to heap.  Does nothing if null.
  2139.       --| Notes:
  2140.       --| This procedure is actually the body for the flush procedure,
  2141.       --| but a generic instantiation cannot be used as a body for another
  2142.       --| procedure.  You tell me why.
  2143.  
  2144.     procedure flush(s: in out string_type) is
  2145.     begin
  2146.         if s /= null then real_flush(s); end if;
  2147.         -- Actually, the if isn't needed; however, DECada compiler chokes
  2148.         -- on deallocation of null.
  2149.     end flush;
  2150.  
  2151.     procedure mark is
  2152.     begin
  2153.         push(scopes, new string_list'(create));
  2154.     end mark;
  2155.  
  2156.     procedure release is
  2157.         procedure flush_list_ptr is
  2158.             new unchecked_deallocation(string_list, string_list_ptr);
  2159.         iter: string_list_pkg.ListIter;
  2160.         top_list: string_list_ptr;
  2161.         s: string_type;
  2162.     begin
  2163.         pop(scopes, top_list);
  2164.         iter := MakeListIter(top_list.all);
  2165.         while more(iter) loop
  2166.             next(iter, s);
  2167.             flush(s);             -- real_flush is bad, DECada bug
  2168. --          real_flush(s);            
  2169.         end loop;
  2170.         destroy(top_list.all);
  2171.         flush_list_ptr(top_list);
  2172.     exception
  2173.         when empty_stack =>
  2174.             raise illegal_dealloc;
  2175.     end release;
  2176.     
  2177.     
  2178. -- Queries:
  2179.  
  2180.     function is_empty(s: in string_type)
  2181.         return boolean is
  2182.     begin
  2183.         return (s = null) or else (s.all = "");
  2184.     end is_empty;
  2185.  
  2186.     function length(s: in string_type)
  2187.         return natural is
  2188.     begin
  2189.     if s = null then return 0; end if; 
  2190.         return(s.all'length);
  2191.     end length;
  2192.  
  2193.     function value(s: in string_type)
  2194.         return string is
  2195.         subtype null_range is positive range 1..0;
  2196.         subtype null_string is string(null_range);
  2197.     begin
  2198.     if s = null then return null_string'(""); end if; 
  2199.         return s.all;
  2200.     end value;
  2201.  
  2202.     function fetch(s: in string_type; i: in positive)
  2203.         return character is
  2204.     begin
  2205.     if is_empty(s) or else (i not in s'range) then raise bounds; end if; 
  2206.         return s(i);
  2207.     end fetch;
  2208.  
  2209.     procedure set_comparison_option(choice: in comparison_option) is
  2210.     begin
  2211.     current_comparison_option := choice; 
  2212.     end set_comparison_option;
  2213.  
  2214.     function get_comparison_option
  2215.     return comparison_option is
  2216.     begin
  2217.     return current_comparison_option; 
  2218.     end get_comparison_option;
  2219.  
  2220.     function equal(s1, s2: in string_type)
  2221.         return boolean is
  2222.     begin
  2223.         if is_empty(s1) then return is_empty(s2); end if; 
  2224.         return (s2 /= null) and then string_equal(s1.all, s2.all);
  2225.     end equal;
  2226.  
  2227.     function equal(s1: in string_type; s2: in string)
  2228.         return boolean is
  2229.     begin
  2230.     if s1 = null then return s2 = ""; end if;
  2231.         return string_equal(s1.all, s2);
  2232.     end equal;
  2233.  
  2234.     function equal(s1: in string; s2: in string_type)
  2235.         return boolean is
  2236.     begin
  2237.     if s2 = null then return s1 = ""; end if;
  2238.         return string_equal(s1, s2.all);
  2239.     end equal;
  2240.  
  2241.     function "<"(s1, s2: in string_type)
  2242.         return boolean is
  2243.     begin
  2244.         if is_empty(s1) then
  2245.         return (not is_empty(s2));
  2246.     else
  2247.         return (s1.all < s2);
  2248.     end if; 
  2249.     end "<";
  2250.  
  2251.     function "<"(s1: in string_type; s2: in string)
  2252.         return boolean is 
  2253.     begin
  2254.     if s1 = null then return s2 /= ""; end if; 
  2255.         return string_less(s1.all, s2);
  2256.     end "<";
  2257.  
  2258.     function "<"(s1: in string; s2: in string_type)
  2259.         return boolean is 
  2260.     begin
  2261.     if s2 = null then return false; end if; 
  2262.         return string_less(s1, s2.all);
  2263.     end "<";
  2264.  
  2265.     function "<="(s1, s2: in string_type)
  2266.         return boolean is 
  2267.     begin
  2268.     if is_empty(s1) then return true; end if; 
  2269.     return (s1.all <= s2); 
  2270.     end "<=";
  2271.  
  2272.     function "<="(s1: in string_type; s2: in string)
  2273.         return boolean is 
  2274.     begin
  2275.     if s1 = null then return true; end if; 
  2276.         return string_less_or_equal(s1.all, s2);
  2277.     end "<=";
  2278.  
  2279.     function "<="(s1: in string; s2: in string_type)
  2280.         return boolean is 
  2281.     begin
  2282.     if s2 = null then return s1 = ""; end if; 
  2283.         return string_less_or_equal(s1, s2.all); 
  2284.     end "<=";
  2285.  
  2286.     function match_c(s: in string_type; c: in character; start: in positive := 1)
  2287.         return natural is
  2288.     begin
  2289.     if s = null then return 0; end if; 
  2290.         for i in start..s.all'last loop
  2291.             if s(i) = c then
  2292.                 return i;
  2293.             end if;
  2294.         end loop;
  2295.         return 0;
  2296.     end match_c;
  2297.  
  2298.     function match_not_c(s: in string_type; c: in character; start: in positive := 1)
  2299.         return natural is
  2300.     begin
  2301.     if s = null then return 0; end if; 
  2302.         for i in start..s.all'last loop
  2303.         if s(i) /= c then
  2304.         return i;
  2305.         end if;
  2306.         end loop;
  2307.     return 0;
  2308.     end match_not_c;
  2309.  
  2310.     function match_s(s1, s2: in string_type; start: in positive := 1)
  2311.         return natural is
  2312.     begin
  2313.     if (s1 = null) or else (s2 = null) then return 0; end if; 
  2314.         return match_string(s1.all, s2.all, start);
  2315.     end match_s;
  2316.  
  2317.     function match_s(s1: in string_type; s2: in string; start: in positive := 1)
  2318.         return natural is
  2319.     begin
  2320.     if s1 = null then return 0; end if; 
  2321.         return match_string(s1.all, s2, start);
  2322.     end match_s;
  2323.  
  2324.     function match_any(s, any: in string_type; start: in positive := 1)
  2325.         return natural is
  2326.     begin
  2327.     if any = null then raise any_empty; end if; 
  2328.         return match_any(s, any.all, start);
  2329.     end match_any;
  2330.  
  2331.     function match_any(s: in string_type; any: in string; start: in positive := 1)
  2332.         return natural is
  2333.     begin
  2334.         if any = "" then raise any_empty; end if;
  2335.         if s = null then return 0; end if;
  2336.  
  2337.         for i in start..s.all'last loop
  2338.             for j in any'range loop
  2339.                 if s(i) = any(j) then
  2340.                     return i;
  2341.                 end if;
  2342.             end loop;
  2343.         end loop;
  2344.         return 0;
  2345.     end match_any;
  2346.  
  2347.     function match_none(s, none: in string_type; start: in positive := 1)
  2348.         return natural is
  2349.     begin
  2350.     if is_empty(s) then return 0; end if; 
  2351.     if is_empty(none) then return 1; end if; 
  2352.  
  2353.         return match_none(s, none.all, start);
  2354.     end match_none;
  2355.  
  2356.     function match_none(s: in string_type; none: in string; start: in positive := 1)
  2357.         return natural is
  2358.         found: boolean;
  2359.     begin
  2360.     if is_empty(s) then return 0; end if; 
  2361.  
  2362.         for i in start..s.all'last loop
  2363.             found := true;
  2364.             for j in none'range loop
  2365.                 if s(i) = none(j) then
  2366.                     found := false;
  2367.                     exit;
  2368.                 end if;
  2369.             end loop;
  2370.             if found then return i; end if;
  2371.         end loop;
  2372.         return 0;
  2373.     end match_none;
  2374.  
  2375.  
  2376.     -- Utilities:
  2377.  
  2378.     function enter(s: in string_type)
  2379.         return string_type is
  2380.     begin
  2381.         top(scopes).all := attach(top(scopes).all, s);
  2382.         return s;
  2383.     exception
  2384.         when empty_stack =>
  2385.             raise illegal_alloc;
  2386.     end enter;
  2387.  
  2388.     function string_lower(s: in string)
  2389.     return string is  
  2390.  
  2391.     begin
  2392.     return CISC.downCase(S);
  2393.  
  2394.     end string_lower; 
  2395.  
  2396.     function string_upper(s: in string)
  2397.     return string is
  2398.  
  2399.     begin
  2400.     return CISC.upCase(S);
  2401.  
  2402.     end string_upper; 
  2403.  
  2404.     function string_equal(s1, s2: in string)
  2405.     return boolean is
  2406.     begin
  2407.     if current_comparison_option = case_sensitive then
  2408.         return s1 = s2;
  2409.     else
  2410.         return CISC.equal(S1, S2);
  2411.     end if;
  2412.  
  2413.     end string_equal;
  2414.  
  2415.     function string_less(s1, s2: in string)
  2416.     return boolean is
  2417.     begin
  2418.     if current_comparison_option = case_sensitive then 
  2419.         return s1 < s2;
  2420.     else
  2421.         return CISC.less(S1, S2);
  2422.     end if;
  2423.  
  2424.     end string_less;
  2425.  
  2426.     function string_less_or_equal(s1, s2: in string)
  2427.     return boolean is
  2428.     begin
  2429.     if current_comparison_option = case_sensitive then 
  2430.         return s1 <= s2;
  2431.     else
  2432.         return CISC.less_or_equal(S1, S2);
  2433.     end if;
  2434.  
  2435.     end string_less_or_equal;
  2436.  
  2437.     function match_string(s1, s2: in string; start: in positive := 1)
  2438.         return natural is
  2439.         offset: natural;
  2440.     begin
  2441.         offset := s2'length - 1;
  2442.         for i in start..(s1'last - offset) loop
  2443.             if s1(i..(i + offset)) = s2 then
  2444.                 return i;
  2445.             end if;
  2446.         end loop;
  2447.         return 0; 
  2448.     exception when constraint_error =>    -- on offset := s2'length (= 0)
  2449.         return 0; 
  2450.     end match_string;
  2451.  
  2452.  
  2453. begin    -- Initialize the scopes stack with an implicit mark.
  2454.     scopes := create;
  2455.     mark;
  2456. end string_pkg;
  2457. --::::::::::
  2458. --sscan.bdy
  2459. --::::::::::
  2460. with String_Pkg;            use String_Pkg;
  2461. with Unchecked_Deallocation;
  2462.  
  2463. package body String_Scanner is
  2464.  
  2465.  
  2466. White_Space   : constant string := " " & ASCII.HT;
  2467. Number_1      : constant string := "0123456789";
  2468. Number        : constant string := Number_1 & "_";
  2469. Quote         : constant string := """";
  2470. Ada_Id_1      : constant string := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  2471. Ada_Id        : constant string := Ada_Id_1 & Number;
  2472.  
  2473. procedure Free_Scanner is
  2474.     new Unchecked_Deallocation(Scan_Record, Scanner);
  2475. function Is_Valid(
  2476.     T : in Scanner
  2477.     ) return boolean is
  2478.  
  2479. begin
  2480.  
  2481.     return T /= null;
  2482.  
  2483. end Is_Valid;
  2484.  
  2485. function Make_Scanner(
  2486.     S : in String_Type
  2487.     ) return Scanner is
  2488.  
  2489.     T : Scanner := new Scan_Record;
  2490.  
  2491. begin
  2492.  
  2493.     T.text := String_Pkg.Make_Persistent(S);
  2494.     return T;
  2495.  
  2496. end Make_Scanner;
  2497.  
  2498. ----------------------------------------------------------------
  2499.  
  2500. procedure Destroy_Scanner(
  2501.     T : in out Scanner
  2502.     ) is
  2503.  
  2504. begin
  2505.  
  2506.     if Is_Valid(T) then
  2507.     String_Pkg.Flush(T.text);
  2508.     Free_Scanner(T);
  2509.     end if;
  2510.  
  2511. end Destroy_Scanner;
  2512.  
  2513. ----------------------------------------------------------------
  2514.  
  2515. function More(
  2516.     T : in Scanner
  2517.     ) return boolean is
  2518.  
  2519. begin
  2520.  
  2521.     if Is_Valid(T) then
  2522.     if T.index > String_Pkg.Length(T.text) then
  2523.         return false;
  2524.     else
  2525.             return true;
  2526.     end if;
  2527.     else
  2528.     return false;
  2529.     end if;
  2530.  
  2531. end More;
  2532.  
  2533. ----------------------------------------------------------------
  2534.  
  2535. function Get(
  2536.     T : in Scanner
  2537.     ) return character is
  2538.  
  2539. begin
  2540.  
  2541.     if not More(T) then
  2542.     raise Out_Of_Bounds;
  2543.     end if;
  2544.     return String_Pkg.Fetch(T.text, T.index);
  2545.  
  2546. end Get;
  2547.  
  2548. ----------------------------------------------------------------
  2549.  
  2550. procedure Forward(
  2551.     T : in Scanner
  2552.     ) is
  2553.  
  2554. begin
  2555.  
  2556.     if Is_Valid(T) then
  2557.     if String_Pkg.Length(T.text) >= T.index then
  2558.         T.index := T.index + 1;
  2559.     end if;
  2560.     end if;
  2561.  
  2562. end Forward;
  2563.  
  2564. ----------------------------------------------------------------
  2565.  
  2566. procedure Backward(
  2567.     T : in Scanner
  2568.     ) is
  2569.  
  2570. begin
  2571.  
  2572.     if Is_Valid(T) then
  2573.     if T.index > 1 then
  2574.         T.index := T.index - 1;
  2575.     end if;
  2576.     end if;
  2577.  
  2578. end Backward;
  2579.  
  2580. ----------------------------------------------------------------
  2581.  
  2582. procedure Next(
  2583.     T : in     Scanner;
  2584.     C :    out character
  2585.     ) is
  2586.  
  2587. begin
  2588.  
  2589.     C := Get(T);
  2590.     Forward(T);
  2591.  
  2592. end Next;
  2593.  
  2594. ----------------------------------------------------------------
  2595.  
  2596. function Position(
  2597.     T : in Scanner
  2598.     ) return positive is
  2599.  
  2600. begin
  2601.  
  2602.     if not More(T) then
  2603.     raise Out_Of_Bounds;
  2604.     end if;
  2605.     return T.index;
  2606.  
  2607. end Position;
  2608.  
  2609. ----------------------------------------------------------------
  2610.  
  2611. function Get_String(
  2612.     T : in Scanner
  2613.     ) return String_Type is
  2614.  
  2615. begin
  2616.  
  2617.     if Is_Valid(T) then
  2618.     return String_Pkg.Make_Persistent(T.text);
  2619.     else
  2620.     return String_Pkg.Make_Persistent("");
  2621.     end if;
  2622.  
  2623. end Get_String;
  2624.  
  2625. ----------------------------------------------------------------
  2626.  
  2627. function Get_Remainder(
  2628.     T : in Scanner
  2629.     ) return String_Type is
  2630.  
  2631.     S_Str : String_Type;
  2632.  
  2633. begin
  2634.  
  2635.     if More(T) then
  2636.     String_Pkg.Mark;
  2637.     S_Str := String_Pkg.Make_Persistent(
  2638.     String_Pkg.Substr(T.text,
  2639.               T.index,
  2640.               String_Pkg.Length(T.text) - T.index + 1));
  2641.     String_Pkg.Release;
  2642.     else
  2643.     S_Str := String_Pkg.Make_Persistent("");
  2644.     end if;
  2645.     return S_Str;
  2646.  
  2647. end Get_Remainder;
  2648.  
  2649. ----------------------------------------------------------------
  2650.  
  2651. procedure Mark(
  2652.     T : in Scanner
  2653.     ) is
  2654.  
  2655. begin
  2656.  
  2657.     if Is_Valid(T) then
  2658.     if T.mark /= 0 then
  2659.         raise Scanner_Already_Marked;
  2660.     else
  2661.         T.mark := T.index;
  2662.     end if;
  2663.     end if;
  2664.  
  2665. end Mark;
  2666.  
  2667. ----------------------------------------------------------------
  2668.  
  2669. procedure Restore(
  2670.     T : in Scanner
  2671.     ) is
  2672.  
  2673. begin
  2674.  
  2675.     if Is_Valid(T) then
  2676.     if T.mark /= 0 then
  2677.         T.index := T.mark;
  2678.         T.mark  := 0;
  2679.     end if;
  2680.     end if;
  2681.  
  2682. end Restore;
  2683.  
  2684. function Is_Any(
  2685.     T : in Scanner;
  2686.     Q : in string
  2687.     ) return boolean is
  2688.  
  2689.     N     : natural;
  2690.  
  2691. begin
  2692.  
  2693.     if not More(T) then
  2694.     return false;
  2695.     end if;
  2696.     String_Pkg.Mark;
  2697.     N := String_Pkg.Match_Any(T.text, Q, T.index);
  2698.     if N /= T.index then
  2699.     N := 0;
  2700.     end if;
  2701.     String_Pkg.Release;
  2702.     return N /= 0;
  2703.  
  2704. end Is_Any;
  2705.  
  2706. procedure Scan_Any(
  2707.     T      : in     Scanner;
  2708.     Q      : in     string;
  2709.     Found  :    out boolean;
  2710.     Result : in out String_Type
  2711.     ) is
  2712.  
  2713.     S_Str : String_Type;
  2714.     N     : natural;
  2715.  
  2716. begin
  2717.  
  2718.     if Is_Any(T, Q) then
  2719.     N := String_Pkg.Match_None(T.text, Q, T.index);
  2720.     if N = 0 then
  2721.         N := String_Pkg.Length(T.text) + 1;
  2722.     end if;
  2723.     Result  := Result & String_Pkg.Substr(T.text, T.index, N - T.index);
  2724.     T.index := N;    
  2725.     Found   := true;
  2726.     else
  2727.     Found := false;
  2728.     end if;
  2729.  
  2730. end Scan_Any;
  2731.  
  2732. function Quoted_String(
  2733.     T : in Scanner
  2734.     ) return integer is
  2735.  
  2736.     Count : integer := 0;
  2737.     I     : positive;
  2738.     N     : natural;
  2739.  
  2740. begin
  2741.  
  2742.     if not Is_Valid(T) then
  2743.     return Count;
  2744.     end if;
  2745.     I := T.index;
  2746.     while Is_Any(T, """") loop
  2747.     T.index := T.index + 1;
  2748.     if not More(T) then
  2749.         T.index := I;
  2750.         return 0;
  2751.     end if;
  2752.     String_Pkg.Mark;
  2753.     N := String_Pkg.Match_Any(T.text, """", T.index);
  2754.     String_Pkg.Release;
  2755.     if N = 0 then
  2756.         T.index := I;
  2757.         return 0;
  2758.     end if;
  2759.     T.index := N + 1;
  2760.     end loop;
  2761.     Count := T.index - I;
  2762.     T.index := I;
  2763.     return Count;
  2764.  
  2765. end Quoted_String;
  2766.  
  2767. function Enclosed_String(
  2768.     B : in character;
  2769.     E : in character;
  2770.     T : in Scanner
  2771.     ) return natural is
  2772.  
  2773.     Count : natural := 1;
  2774.     I     : positive;
  2775.     Inx_B : natural;
  2776.     Inx_E : natural;
  2777.     Depth : natural := 1;
  2778.  
  2779. begin
  2780.  
  2781.     if not Is_Any(T, B & "") then
  2782.     return 0;
  2783.     end if;
  2784.     I := T.index;
  2785.     Forward(T);
  2786.     while Depth /= 0 loop
  2787.     if not More(T) then
  2788.         T.index := I;
  2789.         return 0;
  2790.     end if;
  2791.     String_Pkg.Mark;
  2792.     Inx_B   := String_Pkg.Match_Any(T.text, B & "", T.index);
  2793.     Inx_E   := String_Pkg.Match_Any(T.text, E & "", T.index);
  2794.     String_Pkg.Release;
  2795.     if Inx_E = 0 then
  2796.         T.index := I;
  2797.         return 0;
  2798.     end if;
  2799.     if Inx_B /= 0 and then Inx_B < Inx_E then
  2800.         Depth := Depth + 1;
  2801.     else
  2802.         Inx_B := Inx_E;
  2803.         Depth := Depth - 1;
  2804.     end if;
  2805.     T.index := Inx_B + 1;
  2806.     end loop;
  2807.     Count := T.index - I;
  2808.     T.index := I;
  2809.     return Count;
  2810.  
  2811. end Enclosed_String;
  2812.  
  2813. function Is_Word(
  2814.     T : in Scanner
  2815.     ) return boolean is
  2816.  
  2817. begin
  2818.  
  2819.     if not More(T) then
  2820.     return false;
  2821.     else
  2822.     return not Is_Any(T, White_Space);
  2823.     end if;
  2824.  
  2825. end Is_Word;
  2826.  
  2827. ----------------------------------------------------------------
  2828.  
  2829. procedure Scan_Word(
  2830.     T      : in     Scanner;
  2831.     Found  :    out boolean;
  2832.     Result :    out String_Type;
  2833.     Skip   : in     boolean := false
  2834.     ) is
  2835.  
  2836.     S_Str : String_Type;
  2837.     N     : natural;
  2838.  
  2839. begin
  2840.  
  2841.     if Skip then
  2842.     Skip_Space(T);
  2843.     end if;
  2844.     if Is_Word(T) then
  2845.     String_Pkg.Mark;
  2846.     N := String_Pkg.Match_Any(T.text, White_Space, T.index);
  2847.     if N = 0 then
  2848.         N := String_Pkg.Length(T.text) + 1;
  2849.     end if;
  2850.     Result  := String_Pkg.Make_Persistent
  2851.            (String_Pkg.Substr(T.text, T.index, N - T.index));
  2852.     T.index := N;    
  2853.     Found   := true;
  2854.     String_Pkg.Release;
  2855.     else
  2856.     Found   := false;
  2857.     end if;
  2858.     return;
  2859.  
  2860. end Scan_Word;
  2861.  
  2862. function Is_Number(
  2863.     T : in Scanner
  2864.     ) return boolean is
  2865.  
  2866. begin
  2867.  
  2868.     return Is_Any(T, Number_1);
  2869.  
  2870. end Is_Number;
  2871.  
  2872. ----------------------------------------------------------------
  2873.  
  2874. procedure Scan_Number(
  2875.     T      : in     Scanner;
  2876.     Found  :    out boolean;
  2877.     Result :    out String_Type;
  2878.     Skip   : in     boolean := false
  2879.     ) is
  2880.  
  2881.     C     : character;
  2882.     S_Str : String_Type;
  2883.  
  2884. begin
  2885.  
  2886.     if Skip then
  2887.     Skip_Space(T);
  2888.     end if;
  2889.     if not Is_Number(T) then
  2890.     Found := false;
  2891.     return;
  2892.     end if;
  2893.     String_Pkg.Mark;
  2894.     while Is_Number(T) loop
  2895.     Scan_Any(T, Number_1, Found, S_Str);
  2896.     if More(T) then
  2897.         C := Get(T);
  2898.         if C = '_' then
  2899.         Forward(T);
  2900.         if Is_Number(T) then
  2901.             S_Str := S_Str & "_";
  2902.         else
  2903.             Backward(T);
  2904.         end if;
  2905.         end if;
  2906.     end if;
  2907.     end loop;
  2908.     Result := String_Pkg.Make_Persistent(S_Str);
  2909.     String_Pkg.Release;
  2910.  
  2911. end Scan_Number;
  2912.  
  2913. ----------------------------------------------------------------
  2914.  
  2915. procedure Scan_Number(
  2916.     T      : in     Scanner;
  2917.     Found  :    out boolean;
  2918.     Result :    out integer;
  2919.     Skip   : in     boolean := false
  2920.     ) is
  2921.  
  2922.     F     : boolean;
  2923.     S_Str : String_Type;
  2924.  
  2925. begin
  2926.  
  2927.     Scan_Number(T, F, S_Str, Skip);
  2928.     if F then
  2929.     Result := integer'value(String_Pkg.Value(S_Str));
  2930.     end if;
  2931.     Found := F;
  2932.  
  2933. end Scan_Number;
  2934.  
  2935. function Is_Signed_Number(
  2936.     T : in Scanner
  2937.     ) return boolean is
  2938.  
  2939.     I : positive;
  2940.     C : character;
  2941.     F : boolean;
  2942.  
  2943. begin
  2944.  
  2945.     if More(T) then
  2946.     I := T.index;
  2947.     C := Get(T);
  2948.     if C = '+' or C = '-' then
  2949.         T.index := T.index + 1;
  2950.     end if;
  2951.     F := Is_Any(T, Number_1);
  2952.     T.index := I;
  2953.     return F;
  2954.     else
  2955.     return false;
  2956.     end if;
  2957.  
  2958. end Is_Signed_Number;
  2959.  
  2960. ----------------------------------------------------------------
  2961.  
  2962. procedure Scan_Signed_Number(
  2963.     T      : in     Scanner;
  2964.     Found  :    out boolean;
  2965.     Result :    out String_Type;
  2966.     Skip   : in     boolean := false
  2967.     ) is
  2968.  
  2969.     C     : character;
  2970.     S_Str : String_Type;
  2971.  
  2972. begin
  2973.  
  2974.     if Skip then
  2975.     Skip_Space(T);
  2976.     end if;
  2977.     if Is_Signed_Number(T) then
  2978.     C := Get(T);
  2979.     if C = '+' or C = '-' then
  2980.         Forward(T);
  2981.     end if;
  2982.     Scan_Number(T, Found, S_Str);
  2983.     String_Pkg.Mark;
  2984.     if C = '+' or C = '-' then
  2985.         Result := String_Pkg.Make_Persistent(("" & C) & S_Str);
  2986.     else
  2987.         Result := String_Pkg.Make_Persistent(S_Str);
  2988.     end if;
  2989.     String_Pkg.Release;
  2990.     String_Pkg.Flush(S_Str);
  2991.     else
  2992.     Found := false;
  2993.     end if;
  2994.  
  2995. end Scan_Signed_Number;
  2996.  
  2997. ----------------------------------------------------------------
  2998.  
  2999. procedure Scan_Signed_Number(
  3000.     T      : in     Scanner;
  3001.     Found  :    out boolean;
  3002.     Result :    out integer;
  3003.     Skip   : in     boolean := false
  3004.     ) is
  3005.  
  3006.     F     : boolean;
  3007.     S_Str : String_Type;
  3008.  
  3009. begin
  3010.  
  3011.     Scan_Signed_Number(T, F, S_Str, Skip);
  3012.     if F then
  3013.     Result := integer'value(String_Pkg.Value(S_Str));
  3014.     end if;
  3015.     Found := F;
  3016.  
  3017. end Scan_Signed_Number;
  3018.  
  3019. function Is_Space(
  3020.     T : in Scanner
  3021.     ) return boolean is
  3022.  
  3023. begin
  3024.  
  3025.     return Is_Any(T, White_Space);
  3026.  
  3027. end Is_Space;
  3028.  
  3029. ----------------------------------------------------------------
  3030.  
  3031. procedure Scan_Space(
  3032.     T      : in     Scanner;
  3033.     Found  :    out boolean;
  3034.     Result :    out String_Type
  3035.     ) is
  3036.  
  3037.     S_Str : String_Type;
  3038.  
  3039. begin
  3040.  
  3041.     String_Pkg.Mark;
  3042.     Scan_Any(T, White_Space, Found, S_Str);
  3043.     Result := String_Pkg.Make_Persistent(S_Str);
  3044.     String_Pkg.Release;
  3045.  
  3046. end Scan_Space;
  3047.  
  3048. ----------------------------------------------------------------
  3049.  
  3050. procedure Skip_Space(
  3051.     T : in Scanner
  3052.     ) is
  3053.  
  3054.     S_Str : String_Type;
  3055.     Found : boolean;
  3056.  
  3057. begin
  3058.  
  3059.     String_Pkg.Mark;
  3060.     Scan_Any(T, White_Space, Found, S_Str);
  3061.     String_Pkg.Release;
  3062.  
  3063. end Skip_Space;
  3064.  
  3065. function Is_Ada_Id(
  3066.     T : in Scanner
  3067.     ) return boolean is
  3068.  
  3069. begin
  3070.  
  3071.     return Is_Any(T, Ada_Id_1);
  3072.  
  3073. end Is_Ada_Id;
  3074.  
  3075. ----------------------------------------------------------------
  3076.  
  3077. procedure Scan_Ada_Id(
  3078.     T      : in     Scanner;
  3079.     Found  :    out boolean;
  3080.     Result :    out String_Type;
  3081.     Skip   : in     boolean := false
  3082.     ) is
  3083.  
  3084.     C     : character;
  3085.     F     : boolean;
  3086.     S_Str : String_Type;
  3087.  
  3088. begin
  3089.  
  3090.     if Skip then
  3091.     Skip_Space(T);
  3092.     end if;
  3093.     if Is_Ada_Id(T) then
  3094.     String_Pkg.Mark;
  3095.     Next(T, C);
  3096.     Scan_Any(T, Ada_Id, F, S_Str);
  3097.     Result := String_Pkg.Make_Persistent(("" & C) & S_Str);
  3098.     Found := true;
  3099.     String_Pkg.Release;
  3100.     else
  3101.     Found := false;
  3102.     end if;
  3103.  
  3104. end Scan_Ada_Id;
  3105.  
  3106. function Is_Quoted(
  3107.     T : in Scanner
  3108.     ) return boolean is
  3109.  
  3110. begin
  3111.  
  3112.     if Quoted_String(T) = 0 then
  3113.     return false;
  3114.     else
  3115.     return true;
  3116.     end if;
  3117.  
  3118. end Is_Quoted;
  3119.  
  3120. ----------------------------------------------------------------
  3121.  
  3122. procedure Scan_Quoted(
  3123.     T      : in     Scanner;
  3124.     Found  :    out boolean;
  3125.     Result :    out String_Type;
  3126.     Skip   : in     boolean := false
  3127.     ) is
  3128.  
  3129.     Count : integer;
  3130.  
  3131. begin
  3132.  
  3133.     if Skip then
  3134.     Skip_Space(T);
  3135.     end if;
  3136.     Count := Quoted_String(T);
  3137.     if Count /= 0 then
  3138.     Count := Count - 2;
  3139.     T.index := T.index + 1;
  3140.     if Count /= 0 then
  3141.         String_Pkg.Mark;
  3142.         Result := String_Pkg.Make_Persistent
  3143.               (String_Pkg.Substr(T.text, T.index, positive(Count)));
  3144.         String_Pkg.Release;
  3145.     else
  3146.         Result := String_Pkg.Make_Persistent("");
  3147.     end if;
  3148.     T.index := T.index + Count + 1;
  3149.     Found := true;
  3150.     else
  3151.     Found := false;
  3152.     end if;
  3153.  
  3154. end Scan_Quoted;
  3155.  
  3156. function Is_Enclosed(
  3157.     B : in character;
  3158.     E : in character;
  3159.     T : in Scanner
  3160.     ) return boolean is
  3161.  
  3162. begin
  3163.  
  3164.     if Enclosed_String(B, E, T) = 0 then
  3165.     return false;
  3166.     else
  3167.     return true;
  3168.     end if;
  3169.  
  3170. end Is_Enclosed;
  3171.  
  3172. ----------------------------------------------------------------
  3173.  
  3174. procedure Scan_Enclosed(
  3175.     B      : in     character;
  3176.     E      : in     character;
  3177.     T      : in     Scanner;
  3178.     Found  :    out boolean;
  3179.     Result :    out String_Type;
  3180.     Skip   : in     boolean := false
  3181.     ) is
  3182.  
  3183.     Count : natural;
  3184.  
  3185. begin
  3186.  
  3187.     if Skip then
  3188.     Skip_Space(T);
  3189.     end if;
  3190.     Count := Enclosed_String(B, E, T);
  3191.     if Count /= 0 then
  3192.     Count := Count - 2;
  3193.     T.index := T.index + 1;
  3194.     if Count /= 0 then
  3195.         String_Pkg.Mark;
  3196.         Result := String_Pkg.Make_Persistent(String_Pkg.Substr(T.text, T.index, positive(Count)));
  3197.         String_Pkg.Release;
  3198.     else
  3199.         Result := String_Pkg.Make_Persistent("");
  3200.     end if;
  3201.     T.index := T.index + Count + 1;
  3202.     Found := true;
  3203.     else
  3204.     Found := false;
  3205.     end if;
  3206.  
  3207. end Scan_Enclosed;
  3208.  
  3209. function Is_Sequence(
  3210.     Chars  : in String_Type;
  3211.     T      : in Scanner
  3212.     ) return boolean is
  3213.  
  3214. begin
  3215.  
  3216.     return Is_Any(T, String_Pkg.Value(Chars));
  3217.  
  3218. end Is_Sequence;
  3219.  
  3220. ----------------------------------------------------------------
  3221.  
  3222. function Is_Sequence(
  3223.     Chars  : in string;
  3224.     T      : in Scanner
  3225.     ) return boolean is
  3226.  
  3227. begin
  3228.  
  3229.     return Is_Any(T, Chars);
  3230.  
  3231. end Is_Sequence;
  3232.  
  3233. ----------------------------------------------------------------
  3234.  
  3235. procedure Scan_Sequence(
  3236.     Chars  : in     String_Type;
  3237.     T      : in     Scanner;
  3238.     Found  :    out boolean;
  3239.     Result :    out String_Type;
  3240.     Skip   : in     boolean := false
  3241.     ) is
  3242.  
  3243.     I     : positive;
  3244.     Count : integer := 0;
  3245.  
  3246. begin
  3247.  
  3248.     if Skip then
  3249.     Skip_Space(T);
  3250.     end if;
  3251.     if not Is_Valid(T) then
  3252.     Found := false;
  3253.     return;
  3254.     end if;
  3255.     I := T.index;
  3256.     while Is_Any(T, Value(Chars)) loop
  3257.     Forward(T);
  3258.     Count := Count + 1;
  3259.     end loop;
  3260.     if Count /= 0 then
  3261.     String_Pkg.Mark;
  3262.     Result := String_Pkg.Make_Persistent
  3263.           (String_Pkg.Substr(T.text, I, positive(Count)));
  3264.     Found  := true;
  3265.     String_Pkg.Release;
  3266.     else
  3267.     Found := false;
  3268.     end if;
  3269.  
  3270. end Scan_Sequence;
  3271.  
  3272. ----------------------------------------------------------------
  3273.  
  3274. procedure Scan_Sequence(
  3275.     Chars  : in     string;
  3276.     T      : in     Scanner;
  3277.     Found  :    out boolean;
  3278.     Result :    out String_Type;
  3279.     Skip   : in     boolean := false
  3280.     ) is
  3281.  
  3282. begin
  3283.  
  3284.     String_Pkg.Mark;
  3285.     Scan_Sequence(String_Pkg.Create(Chars), T, Found, Result, Skip);
  3286.     String_Pkg.Release;
  3287.  
  3288. end Scan_Sequence;
  3289.  
  3290. function Is_Not_Sequence(
  3291.     Chars  : in String_Type;
  3292.     T      : in Scanner
  3293.     ) return boolean is
  3294.  
  3295.     N : natural;
  3296.  
  3297. begin
  3298.  
  3299.     if not Is_Valid(T) then
  3300.     return false;
  3301.     end if;
  3302.     String_Pkg.Mark;
  3303.     N := String_Pkg.Match_Any(T.text, Chars, T.index);
  3304.     if N = T.index then
  3305.     N := 0;
  3306.     end if;
  3307.     String_Pkg.Release;
  3308.     return N /= 0;
  3309.  
  3310. end Is_Not_Sequence;
  3311.  
  3312. ----------------------------------------------------------------
  3313.  
  3314. function Is_Not_Sequence(
  3315.     Chars  : in string;
  3316.     T      : in Scanner
  3317.     ) return boolean is
  3318.  
  3319. begin
  3320.  
  3321.     return Is_Not_Sequence(String_Pkg.Create(Chars), T);
  3322.  
  3323. end Is_Not_Sequence;
  3324.  
  3325. ----------------------------------------------------------------
  3326.  
  3327. procedure Scan_Not_Sequence(
  3328.     Chars  : in     string;
  3329.     T      : in     Scanner;
  3330.     Found  :    out boolean;
  3331.     Result :    out String_Type;
  3332.     Skip   : in     boolean := false
  3333.     ) is
  3334.  
  3335.     N     : natural;
  3336.  
  3337. begin
  3338.  
  3339.     if Skip then
  3340.     Skip_Space(T);
  3341.     end if;
  3342.     if Is_Not_Sequence(Chars, T) then
  3343.     String_Pkg.Mark;
  3344.     N := String_Pkg.Match_Any(T.text, Chars, T.index);
  3345.     Result := String_Pkg.Make_Persistent
  3346.           (String_Pkg.Substr(T.text, T.index, N - T.index));
  3347.     T.index := N;
  3348.     Found   := true;
  3349.     String_Pkg.Release;
  3350.     else
  3351.     Found := false;
  3352.     end if;
  3353.  
  3354. end Scan_Not_Sequence;
  3355.  
  3356. ----------------------------------------------------------------
  3357.  
  3358. procedure Scan_Not_Sequence(
  3359.     Chars  : in     String_Type;
  3360.     T      : in     Scanner;
  3361.     Found  :    out boolean;
  3362.     Result :    out String_Type;
  3363.     Skip   : in     boolean := false
  3364.     ) is
  3365.  
  3366. begin
  3367.  
  3368.     Scan_Not_Sequence(String_Pkg.Value(Chars), T, Found, Result, Skip);
  3369.  
  3370. end Scan_Not_Sequence;
  3371.  
  3372. function Is_Literal(
  3373.     Chars  : in String_Type;
  3374.     T      : in Scanner
  3375.     ) return boolean is
  3376.  
  3377.     N : natural;
  3378.  
  3379. begin
  3380.  
  3381.     if not Is_Valid(T) then
  3382.     return false;
  3383.     end if;
  3384.     String_Pkg.Mark;
  3385.     N := String_Pkg.Match_S(T.text, Chars, T.index);
  3386.     if N /= T.index then
  3387.     N := 0;
  3388.     end if;
  3389.     String_Pkg.Release;
  3390.     return N /= 0;
  3391.  
  3392. end Is_Literal;
  3393.  
  3394. ----------------------------------------------------------------
  3395.  
  3396. function Is_Literal(
  3397.     Chars  : in string;
  3398.     T      : in Scanner
  3399.     ) return boolean is
  3400.  
  3401.     Found : boolean;
  3402.  
  3403. begin
  3404.  
  3405.     String_Pkg.Mark;
  3406.     Found := Is_Literal(String_Pkg.Create(Chars), T);
  3407.     String_Pkg.Release;
  3408.     return Found;
  3409.  
  3410. end Is_Literal;
  3411.  
  3412. ----------------------------------------------------------------
  3413.  
  3414. procedure Scan_Literal(
  3415.     Chars  : in     String_Type;
  3416.     T      : in     Scanner;
  3417.     Found  :    out boolean;
  3418.     Skip   : in     boolean := false
  3419.     ) is
  3420.  
  3421. begin
  3422.  
  3423.     if Skip then
  3424.     Skip_Space(T);
  3425.     end if;
  3426.     if Is_Literal(Chars, T) then
  3427.     T.index := T.index + String_Pkg.Length(Chars);
  3428.     Found   := true;
  3429.     else
  3430.     Found   := false;
  3431.     end if;
  3432.  
  3433. end Scan_Literal;
  3434.  
  3435. ----------------------------------------------------------------
  3436.  
  3437. procedure Scan_Literal(
  3438.     Chars  : in     string;
  3439.     T      : in     Scanner;
  3440.     Found  :    out boolean;
  3441.     Skip   : in     boolean := false
  3442.     ) is
  3443.  
  3444. begin
  3445.  
  3446.     String_Pkg.Mark;
  3447.     Scan_Literal(String_Pkg.Create(Chars), T, Found, Skip);
  3448.     String_Pkg.Release;
  3449.  
  3450. end Scan_Literal;
  3451.  
  3452. function Is_Not_Literal(
  3453.     Chars : in string;
  3454.     T     : in Scanner
  3455.     ) return boolean is
  3456.  
  3457.     N     : natural;
  3458.  
  3459. begin
  3460.  
  3461.     if not Is_Valid(T) then
  3462.     return false;
  3463.     end if;
  3464.     String_Pkg.Mark;
  3465.     N := String_Pkg.Match_S(T.text, Chars, T.index);
  3466.     if N = T.index then
  3467.     N := 0;
  3468.     end if;
  3469.     String_Pkg.Release;
  3470.     return N /= 0;
  3471.  
  3472. end Is_Not_Literal;
  3473.  
  3474. ----------------------------------------------------------------
  3475.  
  3476. function Is_Not_Literal(
  3477.     Chars : in String_Type;
  3478.     T     : in Scanner
  3479.     ) return boolean is
  3480.  
  3481. begin
  3482.  
  3483.     if not More(T) then
  3484.     return false;
  3485.     end if;
  3486.     return Is_Not_Literal(String_Pkg.Value(Chars), T);
  3487.  
  3488. end Is_Not_Literal;
  3489.  
  3490. ----------------------------------------------------------------
  3491.  
  3492. procedure Scan_Not_Literal(
  3493.     Chars  : in     string;
  3494.     T      : in     Scanner;
  3495.     Found  :    out boolean;
  3496.     Result :    out String_Type;
  3497.     Skip   : in     boolean := false
  3498.     ) is
  3499.  
  3500.     N : natural;
  3501.  
  3502. begin
  3503.  
  3504.     if Skip then
  3505.     Skip_Space(T);
  3506.     end if;
  3507.     if Is_Not_Literal(Chars, T) then
  3508.     String_Pkg.Mark;
  3509.     N := String_Pkg.Match_S(T.text, Chars, T.index);
  3510.     Result := String_Pkg.Make_Persistent(String_Pkg.Substr(T.text, T.index, N - T.index));
  3511.     T.index := N;
  3512.     Found   := true;
  3513.     String_Pkg.Release;
  3514.     else
  3515.     Found := false;
  3516.     return;
  3517.     end if;
  3518.  
  3519. end Scan_Not_Literal;
  3520.  
  3521. ----------------------------------------------------------------
  3522.  
  3523. procedure Scan_Not_Literal(
  3524.     Chars  : in     String_Type;
  3525.     T      : in     Scanner;
  3526.     Found  :    out boolean;
  3527.     Result :    out String_Type;
  3528.     Skip   : in     boolean := false
  3529.     ) is
  3530.  
  3531. begin
  3532.  
  3533.     Scan_Not_Literal(String_Pkg.Value(Chars), T, Found, Result, Skip);
  3534.  
  3535. end Scan_Not_Literal;
  3536.  
  3537.  
  3538. end String_Scanner;
  3539. --::::::::::
  3540. --tod.bdy
  3541. --::::::::::
  3542. with Search_Utilities;  -- Generic searching package.
  3543. package body Tod_Utilities is
  3544.   -- The type declarations below are used throughout the body to store
  3545.   -- time values.
  3546.  
  3547.   type Integer_Duration is range -86_400 .. 86_400;
  3548.   subtype Positive_Duration is Integer_Duration range
  3549.     1 .. Integer_Duration'LAST;
  3550.   subtype Natural_Duration is Integer_Duration range
  3551.     0 .. Integer_Duration'LAST;
  3552.  
  3553.   -- The constants below make for easy conversion of
  3554.   -- CALENDAR.DAY_DURATION values.
  3555.  
  3556.   Noon_Hour                   : constant Positive_Duration := 12;
  3557.   Number_of_Hours_in_Day      : constant Positive_Duration := 24;
  3558.   Number_of_Minutes_in_Hour   : constant Positive_Duration := 60;
  3559.   Number_of_Minutes_in_Day    : constant Positive_Duration :=
  3560.     Number_of_Minutes_in_Hour * Number_of_Hours_in_Day;
  3561.   Number_of_Seconds_in_Minute : constant Positive_Duration := 60;
  3562.   Number_of_Seconds_in_Hour   : constant Positive_Duration :=
  3563.     Number_of_Seconds_in_Minute * Number_of_Minutes_in_Hour;
  3564.   Number_of_Seconds_in_Day    : constant Positive_Duration :=
  3565.     Number_of_Seconds_in_Hour * Number_of_Hours_in_Day;
  3566.   Number_of_Days_in_a_Week    : constant Positive_Duration :=  7;
  3567.   Number_of_Months_in_a_Year  : constant Positive_Duration := 12;
  3568.  
  3569.   -- Constants needed to access the day name field of an external TOD
  3570.   -- representation.
  3571.  
  3572.   Day_Name_Start : constant POSITIVE := 1;
  3573.   Day_Name_End   : constant POSITIVE := 9;
  3574.  
  3575.   -- Constants to make the code more readable.
  3576.  
  3577.   Blank                         : constant CHARACTER := ' ';
  3578.   Colon                         : constant CHARACTER := ASCII.COLON;
  3579.   Period                        : constant CHARACTER := '.';
  3580.   Max_Legal_Letter_Token_Length : constant POSITIVE  := 9;
  3581.   Version_Number                : constant STRING    := "2.0 (THEB048)";
  3582.   AM_String                     : constant STRING    := "AM";
  3583.   PM_String                     : constant STRING    := "PM";
  3584.   UC_LC_Offset                  : constant NATURAL   :=
  3585.     CHARACTER'POS (ASCII.LC_A) - CHARACTER'POS ('A');
  3586.  
  3587.   -- Types/subtypes and constant array needed by both conversion functions.
  3588.  
  3589.   subtype Set_of_Upper_Case_Letters is CHARACTER range 'A' .. 'Z';
  3590.   subtype Search_Value_Type is STRING (1 .. Max_Legal_Letter_Token_Length);
  3591.   type Month_Name_Array_Type is array (INTEGER range <>) of
  3592.     Search_Value_Type;
  3593.  
  3594.   Month_Name_Array : constant Month_Name_Array_Type (CALENDAR.MONTH_NUMBER) :=
  3595.     ("JANUARY  ", "FEBRUARY ", "MARCH    ", "APRIL    ", "MAY      ",
  3596.      "JUNE     ", "JULY     ", "AUGUST   ", "SEPTEMBER", "OCTOBER  ",
  3597.      "NOVEMBER ", "DECEMBER ");
  3598.  
  3599.   function Version return STRING is
  3600.   begin
  3601.     return Version_Number;
  3602.   end Version;
  3603.  
  3604.   -- The function below uses an algorithm to derive the current day
  3605.   -- of the week given a date (in internal format).
  3606.  
  3607.   function Compute_Day_of_Week (Tod_Value : in CALENDAR.TIME)
  3608.     return Search_Value_Type is
  3609.  
  3610.     -- This function was designed by A. Spencer Peterson, SEI according
  3611.     -- to the author's specifications.  Only extremely minor changes
  3612.     -- were made to the algorithm by the author.
  3613.  
  3614.     -- The following constant hardcodes the algorithm to work at the
  3615.     -- reference point of 1984.  Other hardcoded constants in the
  3616.     -- code nail the exact day, 1/1/84, to Sunday.  If the reference
  3617.     -- point is changed, then so must the day names returned.
  3618.  
  3619.     Ref_Year : constant CALENDAR.YEAR_NUMBER := 1984;
  3620.  
  3621.     Number_of_Days_in_a_Leap_Year     : constant Positive_Duration := 366;
  3622.     Number_of_Days_in_a_Normal_Year   : constant Positive_Duration := 365;
  3623.     Number_of_Days_in_Feb_Leap_Year   : constant Positive_Duration :=  29;
  3624.     Number_of_Days_in_Feb_Normal_Year : constant Positive_Duration :=  28;
  3625.     Number_of_Days_in_Long_Months     : constant Positive_Duration :=  31;
  3626.     Number_of_Days_in_Short_Months    : constant Positive_Duration :=  30;
  3627.  
  3628.     February  : constant POSITIVE :=   2;
  3629.     April     : constant POSITIVE :=   4;
  3630.     June      : constant POSITIVE :=   6;
  3631.     September : constant POSITIVE :=   9;
  3632.     November  : constant POSITIVE :=  11;
  3633.  
  3634.     subtype Number_of_Days_Type is Integer_Duration
  3635.       range -Number_of_Days_in_a_Week + 1 .. Number_of_Days_in_a_Week - 1;
  3636.  
  3637.     First_Year,
  3638.     Last_Year,
  3639.     Input_Year           : CALENDAR.YEAR_NUMBER;
  3640.     Month_Count,
  3641.     Input_Month          : CALENDAR.MONTH_NUMBER;
  3642.     Input_Day            : CALENDAR.DAY_NUMBER;
  3643.     After_Ref_Year       : BOOLEAN;
  3644.     Constrained_Num_Days : Number_of_Days_Type;
  3645.     Number_of_Days       : Integer_Duration := 0;
  3646.  
  3647.     function Leap_Year (In_Year : in CALENDAR.YEAR_NUMBER) return BOOLEAN is
  3648.       Leap_Year_Century : constant POSITIVE := 400;
  3649.       Leap_Year_Offset  : constant POSITIVE :=   4;
  3650.       Century           : constant POSITIVE := 100;
  3651.     begin
  3652.       return (In_Year rem Leap_Year_Century = 0) or
  3653.              ((In_Year rem Leap_Year_Offset = 0) and
  3654.               (In_Year rem Century /= 0));
  3655.     end Leap_Year;
  3656.   begin  -- Compute_Day_of_Week
  3657.     -- Decode the CALENDAR.TIME into its subcomponents.
  3658.  
  3659.     Input_Year  := CALENDAR.YEAR (Tod_Value);
  3660.     Input_Month := CALENDAR.MONTH (Tod_Value);
  3661.     Input_Day   := CALENDAR.DAY (Tod_Value);
  3662.  
  3663.     -- Start of the algorithm follows below.
  3664.  
  3665.     if Input_Year < Ref_Year then
  3666.       After_Ref_Year := FALSE;
  3667.       First_Year     := Input_Year;
  3668.       Last_Year      := Ref_Year;
  3669.     else
  3670.       After_Ref_Year := TRUE;
  3671.       First_Year     := Ref_Year;
  3672.       Last_Year      := Input_Year;
  3673.     end if;
  3674.  
  3675.     while First_Year < Last_Year loop
  3676.       if Leap_Year (First_Year) then
  3677.         if After_Ref_Year then
  3678.           Number_of_Days := Number_of_Days + Number_of_Days_in_a_Leap_Year;
  3679.         else
  3680.           Number_of_Days := Number_of_Days - Number_of_Days_in_a_Leap_Year;
  3681.         end if;
  3682.       elsif After_Ref_Year then
  3683.         Number_of_Days := Number_of_Days + Number_of_Days_in_a_Normal_Year;
  3684.       else
  3685.         Number_of_Days := Number_of_Days - Number_of_Days_in_a_Normal_Year;
  3686.       end if;
  3687.  
  3688.       First_Year := First_Year + 1;
  3689.     end loop;
  3690.  
  3691.     Month_Count := 1;
  3692.  
  3693.     while Month_Count < Input_Month loop
  3694.       case Month_Count is
  3695.         when February =>
  3696.           if Leap_Year (Input_Year) then
  3697.             Number_of_Days := Number_of_Days + Number_of_Days_in_Feb_Leap_Year;
  3698.           else
  3699.             Number_of_Days := Number_of_Days +
  3700.               Number_of_Days_in_Feb_Normal_Year;
  3701.           end if;
  3702.         when April | June | September | November =>
  3703.           Number_of_Days := Number_of_Days + Number_of_Days_in_Short_Months;
  3704.         when others =>
  3705.           Number_of_Days := Number_of_Days + Number_of_Days_in_Long_Months;
  3706.       end case;
  3707.  
  3708.       Month_Count := Month_Count + 1;
  3709.     end loop;
  3710.  
  3711.     Constrained_Num_Days := (Number_of_Days +
  3712.       Integer_Duration (Input_Day)) rem Number_of_Days_in_a_Week;
  3713.  
  3714.     case Constrained_Num_Days is
  3715.       when -6 => return "SUNDAY   ";
  3716.       when -5 => return "MONDAY   ";
  3717.       when -4 => return "TUESDAY  ";
  3718.       when -3 => return "WEDNESDAY";
  3719.       when -2 => return "THURSDAY ";
  3720.       when -1 => return "FRIDAY   ";
  3721.       when  0 => return "SATURDAY ";
  3722.       when  1 => return "SUNDAY   ";  -- The algorithm is hardcoded on this day.
  3723.       when  2 => return "MONDAY   ";
  3724.       when  3 => return "TUESDAY  ";
  3725.       when  4 => return "WEDNESDAY";
  3726.       when  5 => return "THURSDAY ";
  3727.       when  6 => return "FRIDAY   ";
  3728.     end case;
  3729.   end Compute_Day_of_Week;
  3730.  
  3731.   -- The function below converts an internal CALENDAR.TIME value to
  3732.   -- an external STRING value.
  3733.  
  3734.   function Convert (
  3735.     Tod_Value       : in CALENDAR.TIME;
  3736.     Default_Setting : in Type_Set := UPPER_CASE)
  3737.     return External_Tod_Representation_Type is
  3738.  
  3739.     -- Constants for array positions of each component of the external
  3740.     -- representation type follow below.
  3741.  
  3742.     Day_Number_Start  : constant POSITIVE := 11;
  3743.     Day_Number_End    : constant POSITIVE := 12;
  3744.     Month_Name_Start  : constant POSITIVE := 14;
  3745.     Month_Name_End    : constant POSITIVE := 22;
  3746.     Year_Number_Start : constant POSITIVE := 24;
  3747.     Year_Number_End   : constant POSITIVE := 27;
  3748.     Time_Start        : constant POSITIVE := 29;
  3749.     Time_End          : constant POSITIVE := 38;
  3750.     Hour_Start        : constant POSITIVE := 29;
  3751.     Hour_End          : constant POSITIVE := 30;
  3752.     Minute_Start      : constant POSITIVE := 32;
  3753.     Minute_End        : constant POSITIVE := 33;
  3754.     Second_Start      : constant POSITIVE := 35;
  3755.     Second_End        : constant POSITIVE := 36;
  3756.     AMPM_Start        : constant POSITIVE := 37;
  3757.     AMPM_End          : constant POSITIVE := 38;
  3758.  
  3759.     Leading_Zero : constant CHARACTER := '0';
  3760.  
  3761.     subtype Double_Digits is Natural_Duration range 10 .. Natural_Duration'LAST;
  3762.     subtype Afternoon_or_Evening is Natural_Duration range
  3763.       Noon_Hour .. Number_of_Hours_in_Day - 1;
  3764.  
  3765.     Year               : CALENDAR.YEAR_NUMBER;
  3766.     Month              : CALENDAR.MONTH_NUMBER;
  3767.     Day                : CALENDAR.DAY_NUMBER;
  3768.     Seconds            : CALENDAR.DAY_DURATION;
  3769.     Curr_Hour          : Natural_Duration range 00 .. Number_of_Hours_in_Day;
  3770.     Curr_Minute        : Natural_Duration range
  3771.       00 .. Number_of_Minutes_in_Hour - 1;
  3772.     Curr_Second        : Natural_Duration range
  3773.       00 .. Number_of_Seconds_in_Minute - 1;
  3774.     Seconds_as_Natural : Natural_Duration range 0 .. Number_of_Seconds_in_Day;
  3775.     Temp_Value,
  3776.     Return_Value       : External_Tod_Representation_Type := (others => Blank);
  3777.  
  3778.     procedure Convert_Upper_Case_to_Lower_Case (Tod_Value : in out STRING) is
  3779.     begin
  3780.       for I in Tod_Value'RANGE loop
  3781.         if Tod_Value (I) in Set_of_Upper_Case_Letters then
  3782.           Tod_Value (I) := CHARACTER'VAL (CHARACTER'POS (Tod_Value(I)) +
  3783.             UC_LC_Offset);
  3784.         end if;
  3785.       end loop;
  3786.     end Convert_Upper_Case_to_Lower_Case;
  3787.  
  3788.     procedure Convert_Upper_Case_to_Mixed_Case (Tod_Value : in out STRING) is
  3789.     begin
  3790.       for I in Tod_Value'FIRST + 1 .. Tod_Value'LAST loop
  3791.         if (Tod_Value (I) in Set_of_Upper_Case_Letters) and
  3792.            (Tod_Value (I-1) /= Blank) then
  3793.           Tod_Value (I) := CHARACTER'VAL (CHARACTER'POS (Tod_Value (I)) +
  3794.             UC_LC_Offset);
  3795.         end if;
  3796.       end loop;
  3797.  
  3798.       -- Special case: AM/PM indicator.
  3799.  
  3800.       Tod_Value (AMPM_Start) := CHARACTER'VAL (CHARACTER'POS (Tod_Value (
  3801.         AMPM_Start)) - UC_LC_Offset);
  3802.     end Convert_Upper_Case_to_Mixed_Case;
  3803.   begin  -- Convert
  3804.     -- Store day of the week string.
  3805.  
  3806.     Return_Value (Day_Name_Start .. Day_Name_End) :=
  3807.       Compute_Day_of_Week (Tod_Value);
  3808.  
  3809.     -- Disect internal format into its components for our own use.
  3810.  
  3811.     CALENDAR.SPLIT (Tod_Value, Year, Month, Day, Seconds);
  3812.  
  3813.     -- Store day number value.
  3814.  
  3815.     if Natural_Duration (Day) in Double_Digits then
  3816.       Temp_Value (Day_Number_Start - 1 .. Day_Number_End) :=
  3817.         CALENDAR.DAY_NUMBER'IMAGE (Day);
  3818.       Return_Value (Day_Number_Start .. Day_Number_End) :=
  3819.         Temp_Value (Day_Number_Start .. Day_Number_End);
  3820.     else
  3821.       Temp_Value (Day_Number_End - 1 .. Day_Number_End) :=
  3822.         CALENDAR.DAY_NUMBER'IMAGE (Day);
  3823.       Return_Value (Day_Number_Start) := Leading_Zero;
  3824.       Return_Value (Day_Number_End) := Temp_Value (Day_Number_End);
  3825.     end if;
  3826.  
  3827.     -- Store the month name and year number.
  3828.  
  3829.     Return_Value (Month_Name_Start .. Month_Name_End) :=
  3830.       Month_Name_Array (Month);
  3831.     Temp_Value (Year_Number_Start - 1 .. Year_Number_End) :=
  3832.       CALENDAR.YEAR_NUMBER'IMAGE (Year);
  3833.     Return_Value (Year_Number_Start .. Year_Number_End) :=
  3834.       Temp_Value (Year_Number_Start .. Year_Number_End);
  3835.  
  3836.     -- Convert CALENDAR.DAY_DURATION value to Natural_Duration for easier
  3837.     -- calculations below.
  3838.  
  3839.     Seconds_as_Natural := Natural_Duration (Seconds);
  3840.  
  3841.     -- Compute the current hour, minutes, and seconds.
  3842.  
  3843.     Curr_Hour := (Seconds_as_Natural / Number_of_Minutes_in_Hour) /
  3844.       Number_of_Seconds_in_Minute;
  3845.     Curr_Minute := (Seconds_as_Natural / Number_of_Minutes_in_Hour) mod
  3846.       Number_of_Seconds_in_Minute;
  3847.     Curr_Second := Seconds_as_Natural -
  3848.       (Curr_Hour * Number_of_Seconds_in_Hour) -
  3849.       (Curr_Minute * Number_of_Minutes_in_Hour);
  3850.  
  3851.     -- Check for AM/PM in current hour and store AM/PM indication.
  3852.  
  3853.     if (Curr_Hour = 00) or (Curr_Hour = Number_of_Hours_in_Day) then
  3854.       Curr_Hour := Noon_Hour;  -- 00:00:00 === 12:00:00 AM === 24:00:00
  3855.       Return_Value (AMPM_Start .. AMPM_End) := AM_String;
  3856.     elsif (Curr_Hour in Afternoon_or_Evening) and (Curr_Hour /= Noon_Hour) then
  3857.       Curr_Hour := Curr_Hour - Noon_Hour;  -- Convert to AM/PM format.
  3858.       Return_Value (AMPM_Start .. AMPM_End) := PM_String;
  3859.     elsif Curr_Hour = Noon_Hour then
  3860.       Return_Value (AMPM_Start .. AMPM_End) := PM_String;
  3861.     else
  3862.       Return_Value (AMPM_Start .. AMPM_End) := AM_String;
  3863.     end if;
  3864.  
  3865.     -- Store current hour.
  3866.  
  3867.     if Curr_Hour in Double_Digits then
  3868.       Temp_Value (Hour_Start - 1 .. Hour_End) :=
  3869.         Natural_Duration'IMAGE (Curr_Hour);
  3870.       Return_Value (Hour_Start .. Hour_End) :=
  3871.         Temp_Value (Hour_Start .. Hour_End);
  3872.     else
  3873.       Temp_Value (Hour_End - 1 .. Hour_End) :=
  3874.         Natural_Duration'IMAGE (Curr_Hour);
  3875.       Return_Value (Hour_Start) := Leading_Zero;
  3876.       Return_Value (Hour_End) := Temp_Value (Hour_End);
  3877.     end if;
  3878.  
  3879.     Return_Value (Hour_End + 1) := Colon;
  3880.  
  3881.     -- Store current minutes.
  3882.  
  3883.     if Curr_Minute in Double_Digits then
  3884.       Temp_Value (Minute_Start - 1 .. Minute_End) :=
  3885.         Natural_Duration'IMAGE (Curr_Minute);
  3886.       Return_Value (Minute_Start .. Minute_End) :=
  3887.         Temp_Value (Minute_Start .. Minute_End);
  3888.     else
  3889.       Temp_Value (Minute_End - 1 .. Minute_End) :=
  3890.         Natural_Duration'IMAGE (Curr_Minute);
  3891.       Return_Value (Minute_Start) := Leading_Zero;
  3892.       Return_Value (Minute_End) := Temp_Value (Minute_End);
  3893.     end if;
  3894.  
  3895.     Return_Value (Minute_End + 1) := Colon;
  3896.  
  3897.     -- Store current seconds.
  3898.  
  3899.     if Curr_Second in Double_Digits then
  3900.       Temp_Value (Second_Start - 1 .. Second_End) :=
  3901.         Natural_Duration'IMAGE (Curr_Second);
  3902.       Return_Value (Second_Start .. Second_End) :=
  3903.         Temp_Value (Second_Start .. Second_End);
  3904.     else
  3905.       Temp_Value (Second_End - 1 .. Second_End) :=
  3906.         Natural_Duration'IMAGE (Curr_Second);
  3907.       Return_Value (Second_Start) := Leading_Zero;
  3908.       Return_Value (Second_End) := Temp_Value (Second_End);
  3909.     end if;
  3910.  
  3911.     -- Set non-default type set for the user.
  3912.  
  3913.     if Default_Setting = lower_case then
  3914.       Convert_Upper_Case_to_Lower_Case (Return_Value);
  3915.     elsif Default_Setting = Mixed_Case then
  3916.       Convert_Upper_Case_to_Mixed_Case (Return_Value);
  3917.     end if;
  3918.  
  3919.     -- We are done.  Return the external format to the user.
  3920.  
  3921.     return Return_Value;
  3922.   end Convert;
  3923.  
  3924.   -- The function below is equivalent to calling the
  3925.   -- above Convert function with an argument of Calendar.Clock
  3926.   -- to obtain the current date and time.
  3927.   function Now (Default_Setting : in TYPE_SET := UPPER_CASE)
  3928.     return EXTERNAL_TOD_REPRESENTATION_TYPE is
  3929.   begin -- Now
  3930.     return Convert (Calendar.Clock, Default_Setting);
  3931.   end Now;
  3932.  
  3933.   -- The function below converts an external format TOD to the Ada
  3934.   -- internal format, CALENDAR.TIME.
  3935.  
  3936.   function Convert (Tod_String : in STRING) return CALENDAR.TIME is
  3937.     Comma                     : constant CHARACTER     := ',';
  3938.     Minus                     : constant CHARACTER     := '-';
  3939.     Slash                     : constant CHARACTER     := '/';
  3940.     Current_Time              : constant CALENDAR.TIME := CALENDAR.CLOCK;
  3941.     Minimum_Tod_String_Length : constant POSITIVE      := 2;
  3942.  
  3943.     subtype Tod_Value_Length_Type is NATURAL range
  3944.       0 .. Tod_String'LENGTH;
  3945.     subtype Tod_Value_Pointer_Type is POSITIVE range
  3946.        Tod_String'FIRST .. Tod_String'LAST + 1;
  3947.  
  3948.     type Token_Type is (Day_as_Name, Day_as_Number, Month_Name_or_Number,
  3949.       Year_Number, Time_String, Special_Format);
  3950.     type Tokens_Specified_Array_Type is array (Token_Type) of BOOLEAN;
  3951.  
  3952.     Tod_Value                    : STRING (Tod_String'RANGE) := Tod_String;
  3953.     Tod_Value_Compressed_Length,
  3954.     Token_Length                 : Tod_Value_Length_Type;
  3955.     Token                        : STRING (Tod_Value'RANGE);
  3956.     Day_Name                     : Search_Value_Type;
  3957.     No_Token_Found               : BOOLEAN;
  3958.     Tod_Value_Pointer            : Tod_Value_Pointer_Type      :=
  3959.       Tod_Value'FIRST;
  3960.     Year                         : CALENDAR.YEAR_NUMBER        :=
  3961.       CALENDAR.YEAR (Current_Time);
  3962.     Month                        : CALENDAR.MONTH_NUMBER       :=
  3963.       CALENDAR.MONTH (Current_Time);
  3964.     Day                          : CALENDAR.DAY_NUMBER         :=
  3965.       CALENDAR.DAY (Current_Time);
  3966.     Seconds                      : CALENDAR.DAY_DURATION       :=
  3967.       CALENDAR.DAY_DURATION'FIRST;
  3968.     Return_Time_Value            : CALENDAR.TIME               :=
  3969.       CALENDAR.TIME_OF (Year, Month, Day, CALENDAR.DAY_DURATION'FIRST);
  3970.     Tokens_Specified_Array       : Tokens_Specified_Array_Type :=
  3971.       (others => FALSE);
  3972.  
  3973.     function "+" (Left : in CALENDAR.TIME; Right : in DURATION)
  3974.       return CALENDAR.TIME renames CALENDAR."+";
  3975.     function "-" (Left : in CALENDAR.TIME; Right : in DURATION)
  3976.       return CALENDAR.TIME renames CALENDAR."-";
  3977.  
  3978.     procedure Compress_External_Representation (
  3979.       Tod_Value                   : in out STRING;
  3980.       Tod_Value_Compressed_Length :    out Tod_Value_Length_Type) is
  3981.  
  3982.       Tod_Value_Copy         : STRING (Tod_Value'RANGE) := (others => Blank);
  3983.       Tod_Value_Pointer,
  3984.       Tod_Value_Pointer_Copy : Tod_Value_Pointer_Type := Tod_Value'FIRST;
  3985.     begin
  3986.       -- Change all commas to blanks and all minus signs to slash
  3987.       -- signs for easier parsing.
  3988.  
  3989.       for I in Tod_Value'RANGE loop
  3990.         if Tod_Value (I) = Comma then
  3991.           Tod_Value (I) := Blank;
  3992.         elsif Tod_Value (I) = Minus then
  3993.           Tod_Value (I) := Slash;
  3994.         end if;
  3995.       end loop;
  3996.  
  3997.       -- Skip over leading blanks.
  3998.  
  3999.       while (Tod_Value_Pointer <= Tod_Value'LAST) and then
  4000.             (Tod_Value(Tod_Value_Pointer) = Blank) loop
  4001.         Tod_Value_Pointer := Tod_Value_Pointer + 1;
  4002.       end loop;
  4003.  
  4004.       -- Skip over excessive number of blanks in the middle of
  4005.       -- the string.
  4006.  
  4007.       while (Tod_Value_Pointer <= Tod_Value'LAST - 2) loop
  4008.         if (Tod_Value (Tod_Value_Pointer)     = Blank) and
  4009.            (Tod_Value (Tod_Value_Pointer + 1) = Blank) and
  4010.            (Tod_Value (Tod_Value_Pointer + 2) = Blank) then
  4011.           Tod_Value_Pointer := Tod_Value_Pointer + 2;
  4012.         elsif (Tod_Value (Tod_Value_Pointer)     = Blank) and
  4013.               (Tod_Value (Tod_Value_Pointer + 1) = Blank) then
  4014.           Tod_Value_Pointer      := Tod_Value_Pointer      + 2;
  4015.           Tod_Value_Pointer_Copy := Tod_Value_Pointer_Copy + 1;
  4016.         elsif (Tod_Value (Tod_Value_Pointer) = Blank) then
  4017.           Tod_Value_Pointer      := Tod_Value_Pointer      + 1;
  4018.           Tod_Value_Pointer_Copy := Tod_Value_Pointer_Copy + 1;
  4019.         else
  4020.           Tod_Value_Copy (Tod_Value_Pointer_Copy) :=
  4021.             Tod_Value (Tod_Value_Pointer);
  4022.           Tod_Value_Pointer      := Tod_Value_Pointer      + 1;
  4023.           Tod_Value_Pointer_Copy := Tod_Value_Pointer_Copy + 1;
  4024.         end if;
  4025.       end loop;
  4026.  
  4027.       -- Now handle special cases near the end of the string.
  4028.  
  4029.       if (Tod_Value'FIRST + Tod_Value'LAST - 1 >= 3) and then
  4030.          ((Tod_Value (Tod_Value'LAST - 2) /= Blank) and
  4031.           (Tod_Value (Tod_Value'LAST - 1)  = Blank) and
  4032.           (Tod_Value (Tod_Value'LAST)     /= Blank)) then
  4033.         Tod_Value_Pointer_Copy := Tod_Value_Pointer_Copy + 1;
  4034.       end if;
  4035.  
  4036.       if (Tod_Value'FIRST + Tod_Value'LAST - 1 >= 2) and then
  4037.          (Tod_Value (Tod_Value'LAST - 1) /= Blank) then
  4038.         Tod_Value_Copy (Tod_Value_Pointer_Copy) :=
  4039.           Tod_Value (Tod_Value'LAST - 1);
  4040.         Tod_Value_Pointer_Copy := Tod_Value_Pointer_Copy + 1;
  4041.       end if;
  4042.  
  4043.       if (Tod_Value'FIRST + Tod_Value'LAST - 1 >= 1) and then
  4044.          (Tod_Value (Tod_Value'LAST) /= Blank) then
  4045.         Tod_Value_Copy (Tod_Value_Pointer_Copy) := Tod_Value (Tod_Value'LAST);
  4046.         Tod_Value_Pointer_Copy := Tod_Value_Pointer_Copy + 1;
  4047.       end if;
  4048.  
  4049.       -- Now return the compressed string and corresponding length.
  4050.  
  4051.       Tod_Value := Tod_Value_Copy;
  4052.       Tod_Value_Compressed_Length := Tod_Value_Pointer_Copy - Tod_Value'FIRST;
  4053.     end Compress_External_Representation;
  4054.  
  4055.     procedure Convert_External_Representation_to_Upper_Case (
  4056.       Tod_Value : in out STRING) is
  4057.  
  4058.       subtype Set_of_Lower_Case_Letters is CHARACTER range
  4059.         ASCII.LC_A .. ASCII.LC_Z;
  4060.     begin
  4061.       -- Loop on all characters in the compressed Tod_Value.  Modify
  4062.       -- all lower case letters to upper case.
  4063.  
  4064.       for I in Tod_Value'FIRST ..
  4065.                Tod_Value'FIRST + Tod_Value_Compressed_Length - 1 loop
  4066.         if Tod_Value (I) in Set_of_Lower_Case_Letters then
  4067.           Tod_Value (I) := CHARACTER'VAL (CHARACTER'POS (Tod_Value (I)) -
  4068.             UC_LC_Offset);
  4069.         end if;
  4070.       end loop;
  4071.     end Convert_External_Representation_to_Upper_Case;
  4072.  
  4073.     procedure Grab_a_Token (
  4074.       Tod_Value         : in     STRING;
  4075.       Tod_Value_Pointer : in out Tod_Value_Pointer_Type;
  4076.       Token             :    out STRING;
  4077.       Token_Length      :    out Tod_Value_Length_Type;
  4078.       No_Token_Found    :    out BOOLEAN) is
  4079.  
  4080.       Local_Token   : STRING (Token'RANGE)   := (others => Blank);
  4081.       Token_Pointer : Tod_Value_Pointer_Type := Local_Token'FIRST;
  4082.     begin
  4083.       -- Grab the next token.
  4084.  
  4085.       while (Tod_Value_Pointer <= Tod_Value_Compressed_Length +
  4086.              Tod_Value'FIRST - 1) and then
  4087.             (Tod_Value (Tod_Value_Pointer) /= Blank) loop
  4088.         Local_Token (Token_Pointer) := Tod_Value (Tod_Value_Pointer);
  4089.         Token_Pointer               := Token_Pointer + 1;
  4090.         Tod_Value_Pointer           := Tod_Value_Pointer + 1;
  4091.       end loop;
  4092.  
  4093.       -- Skip over that blank, but don't skip outside the bounds.
  4094.  
  4095.       if Tod_Value_Pointer < Tod_Value_Pointer_Type'LAST then
  4096.         Tod_Value_Pointer := Tod_Value_Pointer + 1;
  4097.       end if;
  4098.  
  4099.       -- Did we find a token?  Return T/F.  Also return the token and length.
  4100.  
  4101.       No_Token_Found := Local_Token (Local_Token'FIRST) = Blank;
  4102.       Token          := Local_Token;
  4103.       Token_Length   := Token_Pointer - Local_Token'FIRST;
  4104.     end Grab_a_Token;
  4105.  
  4106.     procedure Analyze_and_Process_Token (
  4107.       Token        : in      STRING;
  4108.       Token_Length : in      Tod_Value_Length_Type;
  4109.       Month_Only   : in      BOOLEAN) is
  4110.  
  4111.       Current_Century : constant POSITIVE :=
  4112.        (CALENDAR.YEAR (Current_Time) / 100) * 100;
  4113.  
  4114.       subtype Short_Year_Range is NATURAL range 0 .. 99;
  4115.       subtype Set_of_Numerics is CHARACTER range '0' .. '9';
  4116.  
  4117.       function Token_Contains_Illegal_Characters (
  4118.         Token        : in STRING;
  4119.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4120.  
  4121.         Only_Legals : BOOLEAN := TRUE;  -- Assume the best.
  4122.       begin
  4123.         for I in Token'FIRST .. Token'FIRST + Token_Length - 1 loop
  4124.           Only_Legals := Only_Legals and
  4125.             ((Token (I) in Set_of_Upper_Case_Letters) or
  4126.              (Token (I) in Set_of_Numerics)           or
  4127.              (Token (I) = Colon)                      or
  4128.              (Token (I) = Period)                     or
  4129.              (Token (I) = Slash));
  4130.         end loop;
  4131.  
  4132.         return not Only_Legals;
  4133.       end Token_Contains_Illegal_Characters;
  4134.  
  4135.       function Token_Contains_Only_Letters (
  4136.         Token        : in STRING;
  4137.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4138.  
  4139.         Only_Letters : BOOLEAN := TRUE;   -- Assume the best.
  4140.       begin
  4141.         for I in Token'FIRST .. Token'FIRST + Token_Length - 1 loop
  4142.           -- Check for a period in an abbreviation.  The period can only
  4143.           -- appear as the last character on the token, otherwise the
  4144.           -- token is illegal.
  4145.  
  4146.           if ((Token (I) = Period) and
  4147.               (I /= Token'FIRST + Token_Length - 1)) and then
  4148.              Token (I+1) /= Slash then
  4149.             raise Abbreviation_Error;
  4150.           end if;
  4151.  
  4152.           -- Now check to make sure that the current character being
  4153.           -- checked is a letter.
  4154.  
  4155.           Only_Letters := Only_Letters and
  4156.             ((Token (I) in Set_of_Upper_Case_Letters) or
  4157.              (Token (I) = Period));
  4158.         end loop;
  4159.  
  4160.         return Only_Letters;
  4161.       end Token_Contains_Only_Letters;
  4162.  
  4163.       function Token_Contains_No_Letters (
  4164.         Token        : in STRING;
  4165.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4166.  
  4167.         No_Letters : BOOLEAN := TRUE;  -- Assume the best.
  4168.       begin
  4169.         for I in Token'FIRST .. Token'FIRST + Token_Length - 1 loop
  4170.           No_Letters := No_Letters and
  4171.                         (Token (I) not in Set_of_Upper_Case_Letters);
  4172.         end loop;
  4173.  
  4174.         return No_Letters;
  4175.       end Token_Contains_No_Letters;
  4176.  
  4177.       function Token_Contains_Only_Numerics (
  4178.         Token        : in STRING;
  4179.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4180.  
  4181.         Only_Numerics : BOOLEAN := TRUE;  -- Assume the best.
  4182.       begin
  4183.         for I in Token'FIRST .. Token'FIRST + Token_Length - 1 loop
  4184.           Only_Numerics := Only_Numerics and (Token (I) in Set_of_Numerics);
  4185.         end loop;
  4186.  
  4187.         return Only_Numerics;
  4188.       end Token_Contains_Only_Numerics;
  4189.  
  4190.       function Token_Contains_Slash (
  4191.         Token        : in STRING;
  4192.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4193.  
  4194.         Slash_Found : BOOLEAN := FALSE;  -- Assume the worst.
  4195.       begin
  4196.         for I in Token'FIRST .. Token'FIRST + Token_Length - 1 loop
  4197.           Slash_Found := Slash_Found or (Token (I) = Slash);
  4198.         end loop;
  4199.  
  4200.         return Slash_Found;
  4201.       end Token_Contains_Slash;
  4202.  
  4203.       function Token_Contains_Colon_and_Numerics_with_Optional_AMPM (
  4204.         Token        : in STRING;
  4205.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4206.  
  4207.         Colon_Found : BOOLEAN := FALSE;  -- Assume the worst.
  4208.         Legal_Token : BOOLEAN := TRUE;   -- Assume the best.
  4209.       begin
  4210.         for I in Token'FIRST .. Token'FIRST + Token_Length - 3 loop
  4211.           if Token (I) /= Colon then
  4212.             Legal_Token := Legal_Token and (Token (I) in Set_of_Numerics);
  4213.           else
  4214.             Colon_Found := TRUE;
  4215.           end if;
  4216.         end loop;
  4217.  
  4218.         if Token_Length < 3 then
  4219.           Legal_Token := FALSE;
  4220.         elsif (Token (Token'FIRST + Token_Length - 2 ..
  4221.                       Token'FIRST + Token_Length - 1) /= AM_String) and
  4222.               (Token (Token'FIRST + Token_Length - 2 ..
  4223.                       Token'FIRST + Token_Length - 1) /= PM_String) then
  4224.           Legal_Token := Legal_Token and
  4225.             (Token (Token'FIRST + Token_Length - 2) in Set_of_Numerics);
  4226.           Legal_Token := Legal_Token and
  4227.             (Token (Token'FIRST + Token_Length - 1) in Set_of_Numerics);
  4228.         end if;
  4229.  
  4230.         return Legal_Token and Colon_Found;
  4231.       end Token_Contains_Colon_and_Numerics_with_Optional_AMPM;
  4232.  
  4233.       function Token_Contains_Numerics_and_AMPM (
  4234.         Token        : in STRING;
  4235.         Token_Length : in Tod_Value_Length_Type) return BOOLEAN is
  4236.  
  4237.         Legal_Token  : BOOLEAN := TRUE;  -- Assume the best.
  4238.       begin
  4239.         for I in Token'FIRST .. Token'FIRST + Token_Length - 3 loop
  4240.           Legal_Token := Legal_Token and (Token (I) in Set_of_Numerics);
  4241.         end loop;
  4242.  
  4243.         if (Token (Token'FIRST + Token_Length - 2 ..
  4244.                    Token'FIRST + Token_Length - 1) /= AM_String) and
  4245.            (Token (Token'FIRST + Token_Length - 2 ..
  4246.                    Token'FIRST + Token_Length - 1) /= PM_String) then
  4247.           Legal_Token := FALSE;
  4248.         end if;
  4249.  
  4250.         return Legal_Token;
  4251.       end Token_Contains_Numerics_and_AMPM;
  4252.  
  4253.       function Convert_Token_to_Proper_Length (Token : in STRING)
  4254.         return Search_Value_Type is
  4255.  
  4256.         Token_Copy : Search_Value_Type := (others => blank);
  4257.         I          : POSITIVE range Token'FIRST .. Token'FIRST +
  4258.           Max_Legal_Letter_Token_Length := Token'FIRST;
  4259.       begin
  4260.         while (I <= Token'FIRST + Max_Legal_Letter_Token_Length - 1) and
  4261.               (I <= Token'LAST) loop
  4262.           Token_Copy (I) := Token (I);
  4263.           I := I + 1;
  4264.         end loop;
  4265.  
  4266.         return Token_Copy;
  4267.       end Convert_Token_to_Proper_Length;
  4268.  
  4269.       procedure Analyze_and_Process_Day_Name_or_Month_Name_or_Special (
  4270.         Token        : in     STRING;
  4271.         Token_Length : in     Tod_Value_Length_Type;
  4272.         Month_Only   : in     BOOLEAN) is
  4273.  
  4274.         Location_Found         : POSITIVE;
  4275.         Component_Found,
  4276.         Abbreviation_Specified : BOOLEAN;
  4277.         Local_Token_Length     : Tod_Value_Length_Type := Token_Length;
  4278.         Local_Token            : Search_Value_Type     :=
  4279.           Convert_Token_to_Proper_Length (Token);
  4280.  
  4281.         -- Establish the arrays of possible days, months, and special
  4282.         -- components.
  4283.  
  4284.         Number_of_Day_Match_Components   : constant POSITIVE := 43;
  4285.         Number_of_Month_Match_Components : constant POSITIVE := 50;
  4286.         Number_of_Special_Components     : constant POSITIVE :=  4;
  4287.  
  4288.         type My_Array_Type is array (POSITIVE range <>) of
  4289.           Search_Value_Type;
  4290.         subtype Day_Match_Array_Index_Type is POSITIVE range
  4291.           1 .. Number_of_Day_Match_Components;
  4292.         subtype Month_Match_Array_Index_Type is POSITIVE range
  4293.           1 .. Number_of_Month_Match_Components;
  4294.         subtype Specials_Array_Index_Type is POSITIVE range
  4295.           1 .. Number_of_Special_Components;
  4296.  
  4297.         Day_Match_Array : constant My_Array_Type (Day_Match_Array_Index_Type) :=
  4298.           ("SU       ", "SUN      ", "SUND     ", "SUNDA    ", "SUNDAY   ",
  4299.            "MO       ", "MON      ", "MOND     ", "MONDA    ", "MONDAY   ",
  4300.            "TU       ", "TUE      ", "TUES     ", "TUESD    ", "TUESDA   ",
  4301.            "TUESDAY  ", "WE       ", "WED      ", "WEDN     ", "WEDNE    ",
  4302.            "WEDNES   ", "WEDNESD  ", "WEDNESDA ", "WEDNESDAY", "TH       ",
  4303.            "THU      ", "THUR     ", "THURS    ", "THURSD   ", "THURSDA  ",
  4304.            "THURSDAY ", "FR       ", "FRI      ", "FRID     ", "FRIDA    ",
  4305.            "FRIDAY   ", "SA       ", "SAT      ", "SATU     ", "SATUR    ",
  4306.            "SATURD   ", "SATURDA  ", "SATURDAY ");
  4307.  
  4308.         Month_Match_Array : constant My_Array_Type (Month_Match_Array_Index_Type) :=
  4309.           ("JAN      ", "JANU     ", "JANUA    ", "JANUAR   ", "JANUARY  ",
  4310.            "FEB      ", "FEBR     ", "FEBRU    ", "FEBRUA   ", "FEBRUAR  ",
  4311.            "FEBRUARY ", "MAR      ", "MARC     ", "MARCH    ", "APR      ",
  4312.            "APRI     ", "APRIL    ", "MAY      ", "JUN      ", "JUNE     ",
  4313.            "JUL      ", "JULY     ", "AUG      ", "AUGU     ", "AUGUS    ",
  4314.            "AUGUST   ", "SEP      ", "SEPT     ", "SEPTE    ", "SEPTEM   ",
  4315.            "SEPTEMB  ", "SEPTEMBE ", "SEPTEMBER", "OCT      ", "OCTO     ",
  4316.            "OCTOB    ", "OCTOBE   ", "OCTOBER  ", "NOV      ", "NOVE     ",
  4317.            "NOVEM    ", "NOVEMB   ", "NOVEMBE  ", "NOVEMBER ", "DEC      ",
  4318.            "DECE     ", "DECEM    ", "DECEMB   ", "DECEMBE  ", "DECEMBER ");
  4319.  
  4320.         subtype Sundays is POSITIVE range 1 .. 5;
  4321.         subtype Mondays is POSITIVE range 6 .. 10;
  4322.         subtype Tuesdays is POSITIVE range 11 .. 16;
  4323.         subtype Wednesdays is POSITIVE range 17 .. 24;
  4324.         subtype Thursdays is POSITIVE range 25 .. 31;
  4325.         subtype Fridays is POSITIVE range 32 .. 36;
  4326.         subtype Saturdays is POSITIVE range 37 .. 43;
  4327.         subtype Januarys is POSITIVE range 1 .. 5;
  4328.         subtype Februarys is POSITIVE range 6 .. 11;
  4329.         subtype Marchs is POSITIVE range 12 .. 14;
  4330.         subtype Aprils is POSITIVE range 15 .. 17;
  4331.         subtype Mays is POSITIVE range 18 .. 18;
  4332.         subtype Junes is POSITIVE range 19 .. 20;
  4333.         subtype Julys is POSITIVE range 21 .. 22;
  4334.         subtype Augusts is POSITIVE range 23 .. 26;
  4335.         subtype Septembers is POSITIVE range 27 .. 33;
  4336.         subtype Octobers is POSITIVE range 34 .. 38;
  4337.         subtype Novembers is POSITIVE range 39 .. 44;
  4338.         subtype Decembers is POSITIVE range 45 .. 50;
  4339.  
  4340.         Specials_Array : constant My_Array_Type(Specials_Array_Index_Type) :=
  4341.           ("NOW      ", "TODAY    ", "TOMORROW ", "YESTERDAY");
  4342.  
  4343.         -- Establish an instantiation of the generic search package.
  4344.  
  4345.         package Search_For_Month_or_Day_Name_or_Specials is new
  4346.           Search_Utilities (
  4347.             Component_Type => Search_Value_Type,
  4348.             Index_Type     => POSITIVE,
  4349.             Array_Type     => My_Array_Type);
  4350.  
  4351.         procedure Analyze_and_Process_Day_Name (
  4352.           Token                  : in     STRING;
  4353.           Location_Found         : in     Day_Match_Array_Index_Type;
  4354.           Abbreviation_Specified : in     BOOLEAN) is
  4355.         begin
  4356.           -- Check to see if the day name has already been specified.
  4357.  
  4358.           if Tokens_Specified_Array (Day_as_Name) then
  4359.             raise Duplication_Error;
  4360.           end if;
  4361.  
  4362.           Tokens_Specified_Array (Day_as_Name) := TRUE;
  4363.  
  4364.           -- Now check to make sure that a period did not follow a full name.
  4365.  
  4366.           if Abbreviation_Specified then
  4367.             declare
  4368.               type Array_Type is array (Positive_Duration range <>) of
  4369.                 Search_Value_Type;
  4370.  
  4371.               Days_Array : constant Array_Type (1 .. Number_of_Days_in_a_Week) :=
  4372.                 ("SUNDAY   ", "MONDAY   ", "TUESDAY  ", "WEDNESDAY",
  4373.                  "THURSDAY ", "FRIDAY   ", "SATURDAY ");
  4374.  
  4375.               package Search_For_Full_Day_Name is new Search_Utilities (
  4376.                 Component_Type => Search_Value_Type,
  4377.                 Index_Type     => Positive_Duration,
  4378.                 Array_Type     => Array_Type);
  4379.             begin
  4380.               if Search_For_Full_Day_Name.Search (
  4381.                    Component    => Token,
  4382.                    Search_Array => Days_Array) then
  4383.                 raise Abbreviation_Error;
  4384.               end if;
  4385.             end;
  4386.           end if;
  4387.  
  4388.           -- Now store the day name for future processing.
  4389.  
  4390.           case Location_Found is
  4391.             when Sundays    => Day_Name := "SUNDAY   ";
  4392.             when Mondays    => Day_Name := "MONDAY   ";
  4393.             when Tuesdays   => Day_Name := "TUESDAY  ";
  4394.             when Wednesdays => Day_Name := "WEDNESDAY";
  4395.             when Thursdays  => Day_Name := "THURSDAY ";
  4396.             when Fridays    => Day_Name := "FRIDAY   ";
  4397.             when Saturdays  => Day_Name := "SATURDAY ";
  4398.           end case;
  4399.         end Analyze_and_Process_Day_Name;
  4400.  
  4401.         procedure Analyze_and_Process_Month_Name (
  4402.           Token                  : in     STRING;
  4403.           Location_Found         : in     Month_Match_Array_Index_Type;
  4404.           Abbreviation_Specified : in     BOOLEAN) is
  4405.         begin
  4406.           -- Check to see if the month name has already been specified.
  4407.  
  4408.           if Tokens_Specified_Array (Month_Name_or_Number) then
  4409.             raise Duplication_Error;
  4410.           end if;
  4411.  
  4412.           Tokens_Specified_Array (Month_Name_or_Number) := TRUE;
  4413.  
  4414.           -- Now check to make sure that a period did not follow a full name.
  4415.  
  4416.           if Abbreviation_Specified then
  4417.             declare
  4418.               package Search_For_Full_Month_Name is new Search_Utilities (
  4419.                 Component_Type => Search_Value_Type,
  4420.                 Index_Type     => INTEGER,
  4421.                 Array_Type     => Month_Name_Array_Type);
  4422.             begin
  4423.               if Search_For_Full_Month_Name.Search (
  4424.                    Component    => Token,
  4425.                    Search_Array => Month_Name_Array) then
  4426.                 raise Abbreviation_Error;
  4427.               end if;
  4428.             end;
  4429.           end if;
  4430.  
  4431.           -- Now store the month number.
  4432.  
  4433.           case Location_Found is
  4434.             when Januarys   => Month :=  1;
  4435.             when Februarys  => Month :=  2;
  4436.             when Marchs     => Month :=  3;
  4437.             when Aprils     => Month :=  4;
  4438.             when Mays       => Month :=  5;
  4439.             when Junes      => Month :=  6;
  4440.             when Julys      => Month :=  7;
  4441.             when Augusts    => Month :=  8;
  4442.             when Septembers => Month :=  9;
  4443.             when Octobers   => Month := 10;
  4444.             when Novembers  => Month := 11;
  4445.             when Decembers  => Month := 12;
  4446.           end case;
  4447.         end Analyze_and_Process_Month_Name;
  4448.  
  4449.         procedure Analyze_and_Process_Special (
  4450.           Token                  : in STRING;
  4451.           Abbreviation_Specified : in BOOLEAN) is
  4452.         begin
  4453.           -- Check to see if the special element has already been
  4454.           -- specified or if an illegal period was specified.
  4455.  
  4456.           if Tokens_Specified_Array (Special_Format) then
  4457.             raise Duplication_Error;
  4458.           elsif Abbreviation_Specified then
  4459.             raise Abbreviation_Error;
  4460.           end if;
  4461.  
  4462.           Tokens_Specified_Array (Special_Format) := TRUE;
  4463.  
  4464.           if Token (Token'FIRST..Token'FIRST +
  4465.                     Max_Legal_Letter_Token_Length - 1) = "NOW      " then
  4466.             Return_Time_Value := CALENDAR.CLOCK;
  4467.           elsif Token (Token'FIRST .. Token'FIRST +
  4468.                        Max_Legal_Letter_Token_Length - 1) = "YESTERDAY" then
  4469.             Return_Time_Value :=
  4470.               CALENDAR.TIME_OF (Year, Month, Day, Seconds) -
  4471.               CALENDAR.DAY_DURATION'LAST;
  4472.           elsif Token (Token'FIRST .. Token'FIRST +
  4473.                        Max_Legal_Letter_Token_Length - 1) = "TOMORROW " then
  4474.             Return_Time_Value :=
  4475.               CALENDAR.TIME_OF (Year, Month, Day, Seconds) +
  4476.               CALENDAR.DAY_DURATION'LAST;
  4477.           end if;
  4478.  
  4479.           -- Now store the components of this internal format so that
  4480.           -- they may be used later.
  4481.  
  4482.           Year  := CALENDAR.YEAR (Return_Time_Value);
  4483.           Month := CALENDAR.MONTH (Return_Time_Value);
  4484.           Day   := CALENDAR.DAY (Return_Time_Value);
  4485.         end Analyze_and_Process_Special;
  4486.       begin
  4487.         -- Check for illegal tokens that are too long.
  4488.  
  4489.         if Token_Length > Max_Legal_Letter_Token_Length then
  4490.           raise External_Representation_Error;
  4491.         end if;
  4492.  
  4493.         -- Check to see if an abbreviation has been given.
  4494.  
  4495.         if Local_Token (Local_Token'FIRST + Token_Length - 1) /= Period then
  4496.           Abbreviation_Specified := FALSE;
  4497.         else
  4498.           Local_Token (Local_Token'FIRST + Local_Token_Length - 1) := Blank;
  4499.           Local_Token_Length := Local_Token_Length - 1;
  4500.           Abbreviation_Specified := TRUE;
  4501.         end if;
  4502.  
  4503.         -- Search the array of day names.
  4504.  
  4505.         Search_For_Month_or_Day_Name_or_Specials.Search (
  4506.           Component       => Local_Token,
  4507.           Search_Array    => Day_Match_Array,
  4508.           Location_Found  => Location_Found,
  4509.           Component_Found => Component_Found);
  4510.  
  4511.         if Component_Found and (not Month_Only) then
  4512.           Analyze_and_Process_Day_Name (Local_Token, Location_Found,
  4513.             Abbreviation_Specified);
  4514.         else
  4515.           -- Search the array of month names.
  4516.  
  4517.           Search_For_Month_or_Day_Name_or_Specials.Search (
  4518.             Component       => Local_Token,
  4519.             Search_Array    => Month_Match_Array,
  4520.             Location_Found  => Location_Found,
  4521.             Component_Found => Component_Found);
  4522.  
  4523.           if Component_Found then
  4524.             Analyze_and_Process_Month_Name (Local_Token, Location_Found,
  4525.               Abbreviation_Specified);
  4526.           else
  4527.             -- Search the array of special formats.
  4528.  
  4529.             Search_For_Month_or_Day_Name_or_Specials.Search (
  4530.               Component       => Local_Token,
  4531.               Search_Array    => Specials_Array,
  4532.               Location_Found  => Location_Found,
  4533.               Component_Found => Component_Found);
  4534.  
  4535.             if Component_Found and not Month_Only then
  4536.               Analyze_and_Process_Special (Local_Token,
  4537.                 Abbreviation_Specified);
  4538.             else
  4539.               raise External_Representation_Error;
  4540.             end if;
  4541.           end if;
  4542.         end if;
  4543.       end Analyze_and_Process_Day_Name_or_Month_Name_or_Special;
  4544.  
  4545.       procedure Analyze_and_Process_Day_Number_or_Year_Number (
  4546.         Token        : in     STRING;
  4547.         Token_Length : in     Tod_Value_Length_Type) is
  4548.  
  4549.         Temp_Value : NATURAL;
  4550.       begin
  4551.         begin
  4552.           Temp_Value := NATURAL'VALUE (Token);
  4553.         exception
  4554.           when CONSTRAINT_ERROR => raise External_Representation_Error;
  4555.         end;
  4556.  
  4557.         -- Is the number legal?  If so, store the year/day.
  4558.  
  4559.         if (Temp_Value not in Short_Year_Range) and
  4560.            (Temp_Value not in CALENDAR.YEAR_NUMBER) then
  4561.           raise External_Representation_Error;
  4562.         end if;
  4563.  
  4564.         if Temp_Value in CALENDAR.YEAR_NUMBER then
  4565.           if Tokens_Specified_Array (Year_Number) then
  4566.             raise Duplication_Error;
  4567.           elsif (Tokens_Specified_Array (Month_Name_or_Number) and
  4568.                  (not Tokens_Specified_Array (Day_as_Number))) or
  4569.                 (Tokens_Specified_Array (Day_as_Number) and
  4570.                  (not Tokens_Specified_Array (Month_Name_or_Number))) then
  4571.             raise External_Representation_Error;
  4572.           end if;
  4573.  
  4574.           Tokens_Specified_Array (Year_Number) := TRUE;
  4575.           Year := Temp_Value;
  4576.         elsif (not Tokens_Specified_Array (Day_as_Number)) and
  4577.               (Temp_Value in CALENDAR.DAY_NUMBER) then
  4578.           Tokens_Specified_Array (Day_as_Number) := TRUE;
  4579.           Day := Temp_Value;
  4580.         elsif Tokens_Specified_Array (Year_Number) or
  4581.               (not Tokens_Specified_Array (Month_Name_or_Number)) or
  4582.               (not Tokens_Specified_Array (Day_as_Number)) then
  4583.           raise External_Representation_Error;
  4584.         else
  4585.           Tokens_Specified_Array (Year_Number) := TRUE;
  4586.  
  4587.           -- Special current century check: 00 = 2000 (20th century).
  4588.  
  4589.           if (Temp_Value = 00) and (Current_Century = 1900) then
  4590.             Year := 2000;
  4591.           else
  4592.             Year := Current_Century + Temp_Value;
  4593.           end if;
  4594.         end if;
  4595.       end Analyze_and_Process_Day_Number_or_Year_Number;
  4596.  
  4597.       procedure Analyze_and_Process_Date (
  4598.         Token        : in     STRING;
  4599.         Token_Length : in     Tod_Value_Length_Type) is
  4600.  
  4601.         procedure Analyze_and_Process_Numeric_Date (
  4602.           Token        : in STRING;
  4603.           Token_Length : in Tod_Value_Length_Type) is
  4604.  
  4605.           Curr_Month,
  4606.           Curr_Day,
  4607.           Curr_Year            : NATURAL;
  4608.           Temp_String          : STRING (Token'RANGE) := (others => Blank);
  4609.           Temp_String_Pointer,
  4610.           Token_Pointer        : Tod_Value_Pointer_Type := Token'FIRST;
  4611.         begin
  4612.           if Tokens_Specified_Array (Month_Name_or_Number) then
  4613.             raise Duplication_Error;
  4614.           end if;
  4615.  
  4616.           Tokens_Specified_Array (Month_Name_or_Number) := TRUE;
  4617.  
  4618.           -- Grab the month.  We should only find 1 or 2 characters.
  4619.  
  4620.           while (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4621.                 (Token (Token_Pointer) /= Slash) loop
  4622.             Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4623.             Token_Pointer                     := Token_Pointer + 1;
  4624.             Temp_String_Pointer               := Temp_String_Pointer + 1;
  4625.           end loop;
  4626.  
  4627.           if (Temp_String_Pointer > Temp_String'FIRST + 2) or
  4628.              (Temp_String_Pointer = Temp_String'FIRST) then
  4629.             raise Month_Number_Error;
  4630.           end if;
  4631.  
  4632.           -- Store the month and check its range.
  4633.  
  4634.           begin
  4635.             Curr_Month := NATURAL'VALUE (Temp_String);
  4636.           exception
  4637.             when CONSTRAINT_ERROR => raise Month_Number_Error;
  4638.           end;
  4639.  
  4640.           if Curr_Month not in CALENDAR.MONTH_NUMBER then
  4641.             raise Month_Number_Error;
  4642.           else
  4643.             Month := Curr_Month;
  4644.           end if;
  4645.  
  4646.           if Tokens_Specified_Array (Day_as_Number) then
  4647.             raise Duplication_Error;
  4648.           end if;
  4649.  
  4650.           Tokens_Specified_Array (Day_as_Number) := TRUE;
  4651.  
  4652.           -- Grab the day.  Procedure is the same as above.
  4653.  
  4654.           Token_Pointer       := Token_Pointer + 1;  -- Bump past slash.
  4655.           Temp_String         := (others => Blank);
  4656.           Temp_String_Pointer := Temp_String'FIRST;
  4657.  
  4658.           while (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4659.                 (Token (Token_Pointer) /= Slash) loop
  4660.             Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4661.             Token_Pointer                     := Token_Pointer + 1;
  4662.             Temp_String_Pointer               := Temp_String_Pointer + 1;
  4663.           end loop;
  4664.  
  4665.           if (Temp_String_Pointer > Temp_String'FIRST + 2) or
  4666.              (Temp_String_Pointer = Temp_String'FIRST) then
  4667.             raise Day_Number_Error;
  4668.           end if;
  4669.  
  4670.           -- Store the day and check its range.
  4671.  
  4672.           begin
  4673.             Curr_Day := NATURAL'VALUE (Temp_String);
  4674.           exception
  4675.             when CONSTRAINT_ERROR => raise Day_Number_Error;
  4676.           end;
  4677.  
  4678.           if Curr_Day not in CALENDAR.DAY_NUMBER then
  4679.             raise Day_Number_Error;
  4680.           else
  4681.             Day := Curr_Day;
  4682.           end if;
  4683.  
  4684.           -- Grab the year.  Procedure is the same as above.
  4685.           -- Year is optional, so check for this first.
  4686.  
  4687.           if (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4688.              (Token (Token_Pointer) = Slash) then
  4689.             if Tokens_Specified_Array (Year_Number) then
  4690.               raise Duplication_Error;
  4691.             end if;
  4692.  
  4693.             Tokens_Specified_Array (Year_Number) := TRUE;
  4694.  
  4695.             Token_Pointer       := Token_Pointer + 1;
  4696.             Temp_String         := (others => Blank);
  4697.             Temp_String_Pointer := Temp_String'FIRST;
  4698.  
  4699.             while (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4700.                   (Token (Token_Pointer) /= Slash) loop
  4701.               Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4702.               Token_Pointer                     := Token_Pointer + 1;
  4703.               Temp_String_Pointer               := Temp_String_Pointer + 1;
  4704.             end loop;
  4705.  
  4706.             if (Temp_String_Pointer > Temp_String'FIRST + 4) or
  4707.                (Temp_String_Pointer = Temp_String'FIRST) then
  4708.               raise Year_Error;
  4709.             end if;
  4710.  
  4711.             -- Store the year and check its range.
  4712.  
  4713.             begin
  4714.               Curr_Year := NATURAL'VALUE (Temp_String);
  4715.             exception
  4716.               when CONSTRAINT_ERROR => raise Year_Error;
  4717.             end;
  4718.  
  4719.             if (Curr_Year not in CALENDAR.YEAR_NUMBER) and
  4720.                (Curr_Year not in Short_Year_Range) then
  4721.               raise Year_Error;
  4722.             end if;
  4723.  
  4724.             if Curr_Year in Short_Year_Range then
  4725.               -- Special current century check: 00 = 2000 (20th century).
  4726.  
  4727.               if (Curr_Year = 00) and (Current_Century = 1900) then
  4728.                 Curr_Year := 2000;
  4729.               else
  4730.                 Curr_Year := Current_Century + Curr_Year;
  4731.               end if;
  4732.  
  4733.               -- Special check on the year 1900.
  4734.  
  4735.               if Curr_Year = CALENDAR.YEAR_NUMBER'FIRST - 1 then
  4736.                 raise Year_Error;
  4737.               end if;
  4738.             end if;
  4739.  
  4740.             Year := Curr_Year;
  4741.           end if;
  4742.         end Analyze_and_Process_Numeric_Date;
  4743.  
  4744.         procedure Analyze_and_Process_Combination_Date (
  4745.           Tod_Value        : in     STRING;
  4746.           Tod_Value_Length : in     Tod_Value_Length_Type) is
  4747.  
  4748.           Local_Token        : STRING (Tod_Value'RANGE);
  4749.           Local_Token_Length : Tod_Value_Length_Type;
  4750.           No_Token_Found     : BOOLEAN;
  4751.           Local_Tod_Value    : STRING (Tod_Value'RANGE) := Tod_Value;
  4752.           Tod_Value_Pointer  : Tod_Value_Pointer_Type := Local_Tod_Value'FIRST;
  4753.         begin
  4754.           -- Eliminate the slash sign(s).  Replace them with blanks.
  4755.  
  4756.           for I in Local_Tod_Value'FIRST ..
  4757.                    Local_Tod_Value'FIRST + Tod_Value_Length - 1 loop
  4758.             if Local_Tod_Value (I) = Slash then
  4759.               Local_Tod_Value (I) := Blank;
  4760.             end if;
  4761.           end loop;
  4762.  
  4763.           -- Now process each "token" in turn.  Note the recursion.
  4764.  
  4765.           loop
  4766.             Grab_a_Token (Local_Tod_Value, Tod_Value_Pointer,
  4767.               Local_Token, Local_Token_Length, No_Token_Found);
  4768.  
  4769.             exit when No_Token_Found;
  4770.  
  4771.             Analyze_and_Process_Token (Local_Token, Local_Token_Length, TRUE);
  4772.           end loop;
  4773.         end Analyze_and_Process_Combination_Date;
  4774.       begin
  4775.         -- Check to see if we are dealing with only numerics or not.
  4776.  
  4777.         if Token_Contains_No_Letters (Token, Token_Length) then
  4778.           Analyze_and_Process_Numeric_Date (Token, Token_Length);
  4779.         else
  4780.           Analyze_and_Process_Combination_Date (Token, Token_Length);
  4781.         end if;
  4782.       end Analyze_and_Process_Date;
  4783.  
  4784.       procedure Analyze_and_Process_Time (
  4785.         Token        : in     STRING;
  4786.         Token_Length : in     Tod_Value_Length_Type;
  4787.         Hour_Only    : in     BOOLEAN) is
  4788.  
  4789.         Min_HourAMPM_Length : constant POSITIVE :=  3;
  4790.         Max_HourAMPM_Length : constant POSITIVE :=  4;
  4791.         Min_Time_Length     : constant POSITIVE :=  3;
  4792.         Max_Time_Length     : constant POSITIVE := 10;
  4793.  
  4794.         subtype Hour_AMPM_Range is Positive_Duration range 01 .. Noon_Hour;
  4795.         Curr_Hour            : Natural_Duration;
  4796.         Curr_Minute,
  4797.         Curr_Second          : Natural_Duration := 00;
  4798.         Seconds_as_Natural   : Natural_Duration range
  4799.           0 .. Number_of_Seconds_in_Day;
  4800.         Temp_String          : STRING (Token'RANGE) := (others => Blank);
  4801.         Temp_String_Pointer,
  4802.         Token_Pointer        : Tod_Value_Pointer_Type := Token'FIRST;
  4803.         Special_Hour_Check   : BOOLEAN;
  4804.       begin
  4805.         if Tokens_Specified_Array (Time_String) then
  4806.           raise Duplication_Error;
  4807.         end if;
  4808.  
  4809.         Tokens_Specified_Array (Time_String) := TRUE;
  4810.  
  4811.         -- Check to see if only the hour was specified.
  4812.  
  4813.         if Hour_Only then
  4814.           -- Check length.  Should be either 3 or 4 characters.
  4815.  
  4816.           if (Token_Length < Min_HourAMPM_Length) or
  4817.              (Token_Length > MAx_HourAMPM_Length) then
  4818.             raise Time_String_Error;
  4819.           end if;
  4820.  
  4821.           -- Grab the hour.  Store in temporary string.
  4822.  
  4823.           while Token (Token_Pointer) in Set_of_Numerics loop
  4824.             Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4825.             Token_Pointer                     := Token_Pointer + 1;
  4826.             Temp_String_Pointer               := Temp_String_Pointer + 1;
  4827.           end loop;
  4828.  
  4829.           -- Decode the hour and check the range.
  4830.  
  4831.           begin
  4832.             Curr_Hour := Natural_Duration'VALUE (Temp_String);
  4833.           exception
  4834.             when CONSTRAINT_ERROR => raise Hour_Error;
  4835.           end;
  4836.  
  4837.           if Curr_Hour not in Hour_AMPM_Range then
  4838.             raise Hour_Error;
  4839.           end if;
  4840.  
  4841.           -- Set hours to AM/PM indicator.
  4842.  
  4843.           if Curr_Hour = Noon_Hour then
  4844.             if Token (Token_Pointer .. Token_Pointer + 1) = AM_String then
  4845.               Curr_Hour := 00;
  4846.             else
  4847.               Curr_Hour := Noon_Hour;
  4848.             end if;
  4849.           elsif Token (Token_Pointer .. Token_Pointer + 1) = PM_String then
  4850.             Curr_Hour := Curr_Hour + Noon_Hour;
  4851.           end if;
  4852.         else
  4853.           -- Check length.  Should be between 3 and 10.
  4854.  
  4855.           if (Token_Length < Min_Time_Length) or
  4856.              (Token_Length > Max_Time_Length) then
  4857.             raise Time_String_Error;
  4858.           end if;
  4859.  
  4860.           -- Grab the hours.  Should only find 1 or 2 characters, both
  4861.           -- numerics.
  4862.  
  4863.           while (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4864.                 (Token (Token_Pointer) /= Colon) loop
  4865.             Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4866.             Temp_String_Pointer               := Temp_String_Pointer + 1;
  4867.             Token_Pointer                     := Token_Pointer + 1;
  4868.           end loop;
  4869.  
  4870.           if (Temp_String_Pointer > Temp_String'FIRST + 2) or
  4871.              (Temp_String_Pointer = Temp_String'FIRST) then
  4872.             raise Hour_Error;
  4873.           end if;
  4874.  
  4875.           -- Store the number of hours and check its range.
  4876.  
  4877.           begin
  4878.             Curr_Hour := Natural_Duration'VALUE (Temp_String);
  4879.           exception
  4880.             when CONSTRAINT_ERROR => raise Hour_Error;
  4881.           end;
  4882.  
  4883.           if Curr_Hour not in 00 .. Number_of_Hours_in_Day then
  4884.             raise Hour_Error;
  4885.           end if;
  4886.  
  4887.           if Curr_Hour /= Number_of_Hours_in_Day then
  4888.             Special_Hour_Check := FALSE;
  4889.           else
  4890.             Special_Hour_Check := TRUE;
  4891.             Curr_Hour := 00;
  4892.           end if;
  4893.  
  4894.           -- Grab the minutes.  Procedure is the same as above.
  4895.  
  4896.           Token_Pointer       := Token_Pointer + 1;  -- Bump past colon.
  4897.           Temp_String         := (others => Blank);
  4898.           Temp_String_Pointer := Temp_String'FIRST;
  4899.  
  4900.           while (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4901.                 ((Token (Token_Pointer) /= Colon)                 and
  4902.                  (Token (Token_Pointer) /= 'A')                   and
  4903.                  (Token (Token_Pointer) /= 'P')) loop
  4904.             Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4905.             Temp_String_Pointer := Temp_String_Pointer + 1;
  4906.             Token_Pointer := Token_Pointer + 1;
  4907.           end loop;
  4908.  
  4909.           if Temp_String_Pointer /= Temp_String'FIRST + 2 then
  4910.             raise Minute_Error;
  4911.           end if;
  4912.  
  4913.           -- Store the number of minutes and check its range.
  4914.  
  4915.           begin
  4916.             Curr_Minute := Natural_Duration'VALUE (Temp_String);
  4917.           exception
  4918.             when CONSTRAINT_ERROR => raise Minute_Error;
  4919.           end;
  4920.  
  4921.           if Curr_Minute not in 00 .. Number_of_Minutes_in_Hour - 1 then
  4922.             raise Minute_Error;
  4923.           end if;
  4924.  
  4925.           -- Grab the seconds.  Procedure is the same as above.
  4926.           -- seconds are optional, so check for this first.
  4927.  
  4928.           if (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4929.              (Token(Token_Pointer) = Colon) then
  4930.             Token_Pointer       := Token_Pointer + 1;  -- Bump past colon.
  4931.             Temp_String         := (others => Blank);
  4932.             Temp_String_Pointer := Temp_String'FIRST;
  4933.  
  4934.             while (Token_Pointer <= Token'FIRST + Token_Length - 1) and then
  4935.                   ((Token (Token_Pointer) /= 'A')                   and
  4936.                    (Token (Token_Pointer) /= 'P')) loop
  4937.               if Token (Token_Pointer) = Colon then
  4938.                 raise Time_String_Error;
  4939.               end if;
  4940.  
  4941.               Temp_String (Temp_String_Pointer) := Token (Token_Pointer);
  4942.               Temp_String_Pointer               := Temp_String_Pointer + 1;
  4943.               Token_Pointer                     := Token_Pointer + 1;
  4944.             end loop;
  4945.  
  4946.             if Temp_String_Pointer /= Temp_String'FIRST + 2 then
  4947.               raise Second_Error;
  4948.             end if;
  4949.  
  4950.             -- Store the number of seconds and check its range.
  4951.  
  4952.             begin
  4953.               Curr_Second := Natural_Duration'VALUE (Temp_String);
  4954.             exception
  4955.               when CONSTRAINT_ERROR => raise Second_Error;
  4956.             end;
  4957.  
  4958.             if Curr_Second not in 00 .. Number_of_Seconds_in_Minute - 1 then
  4959.               raise Second_Error;
  4960.             end if;
  4961.           end if;
  4962.  
  4963.           -- Check for optional AM/PM and check against hours specified.
  4964.  
  4965.           if (Token_Pointer /= Token'FIRST + Token_Length - 2) and
  4966.              (Token_Pointer /= Token'FIRST + Token_Length) then
  4967.             raise Time_String_Error;
  4968.           end if;
  4969.  
  4970.            if Token_Pointer = Token'FIRST + Token_Length - 2 then
  4971.              if Curr_Hour not in Hour_AMPM_Range then
  4972.                raise Hour_Error;
  4973.              end if;
  4974.  
  4975.             if Curr_Hour = Noon_Hour then
  4976.               if Token (Token'FIRST + Token_Length - 2 ..
  4977.                         Token'FIRST + Token_Length - 1) = AM_String then
  4978.                 Curr_Hour := 00;
  4979.               else
  4980.                 Curr_Hour := Noon_Hour;
  4981.               end if;
  4982.             elsif Token (Token'FIRST + Token_Length - 2 ..
  4983.                          Token'FIRST + Token_Length - 1) = PM_String then
  4984.               Curr_Hour := Curr_Hour + Noon_Hour;
  4985.             end if;
  4986.           end if;
  4987.         end if;
  4988.  
  4989.         -- Check for illegal time formats with hours equal to 24.
  4990.  
  4991.         if Special_Hour_Check and
  4992.            ((Curr_Minute /= 00) or (Curr_Second /= 00)) then
  4993.           raise Time_String_Error;
  4994.         end if;
  4995.  
  4996.         -- Compute the number of seconds given the components.
  4997.  
  4998.         Seconds_as_Natural := (Curr_Hour * Number_of_Seconds_in_Minute *
  4999.           Number_of_Minutes_in_Hour) +
  5000.           (Curr_Minute * Number_of_Seconds_in_Minute) + Curr_Second;
  5001.  
  5002.         Seconds := CALENDAR.DAY_DURATION (Seconds_as_Natural);
  5003.       end Analyze_and_Process_Time;
  5004.     begin  -- Analyze_and_Process_Token
  5005.       -- Determine what type of token we have.  See if the token contains
  5006.       -- only numerics, letters, etc.  Call the appropriate action
  5007.       -- routine once we have figured out what the token can be.  Also,
  5008.       -- if the token is not of any type that we can recognize, then
  5009.       -- raise External_Representation_Error.
  5010.  
  5011.       if Token_Contains_Illegal_Characters (Token, Token_Length) then
  5012.         raise External_Representation_Error;
  5013.       elsif Token_Contains_Only_Letters (Token, Token_Length) then
  5014.         Analyze_and_Process_Day_Name_or_Month_Name_or_Special (Token,
  5015.           Token_Length, Month_Only);
  5016.       elsif Token_Contains_Only_Numerics (Token, Token_Length) then
  5017.         Analyze_and_Process_Day_Number_or_Year_Number (Token, Token_Length);
  5018.       elsif Token_Contains_Slash (Token, Token_Length) then
  5019.         Analyze_and_Process_Date (Token, Token_Length);
  5020.       elsif Token_Contains_Colon_and_Numerics_with_Optional_AMPM (Token,
  5021.               Token_Length) then
  5022.         Analyze_and_Process_Time(Token, Token_Length, FALSE);
  5023.       elsif Token_Contains_Numerics_and_AMPM (Token, Token_Length) then
  5024.         Analyze_and_Process_Time (Token, Token_Length, TRUE);
  5025.       else
  5026.         raise External_Representation_Error;
  5027.       end if;
  5028.     end Analyze_and_Process_Token;
  5029.  
  5030.     procedure Compute_Current_or_Next_Future_Date_For_a_Day_Name is
  5031.       Tod_String           : External_Tod_Representation_Type :=
  5032.         Convert (Current_Time);
  5033.       Offset               : Natural_Duration range
  5034.         0 .. Number_of_Days_in_a_Week - 1;
  5035.       Target_Day_Position,
  5036.       Current_Day_Position : Positive_Duration range
  5037.         1 .. Number_of_Days_in_a_Week;
  5038.     begin
  5039.       -- Store the current day position.
  5040.  
  5041.       if Tod_String (Day_Name_Start .. Day_Name_End) = "SUNDAY   " then
  5042.         Current_Day_Position := 1;
  5043.       elsif Tod_String (Day_Name_Start .. Day_Name_End) = "MONDAY   " then
  5044.         Current_Day_Position := 2;
  5045.       elsif Tod_String (Day_Name_Start .. Day_Name_End) = "TUESDAY  " then
  5046.         Current_Day_Position := 3;
  5047.       elsif Tod_String (Day_Name_Start .. Day_Name_End) = "WEDNESDAY" then
  5048.         Current_Day_Position := 4;
  5049.       elsif Tod_String (Day_Name_Start .. Day_Name_End) = "THURSDAY " then
  5050.         Current_Day_Position := 5;
  5051.       elsif Tod_String (Day_Name_Start .. Day_Name_End) = "FRIDAY   " then
  5052.         Current_Day_Position := 6;
  5053.       else  -- SATURDAY
  5054.         Current_Day_Position := 7;
  5055.       end if;
  5056.  
  5057.       -- Store the target day position.
  5058.  
  5059.       if Day_Name = "SUNDAY   " then
  5060.         Target_Day_Position := 1;
  5061.       elsif Day_Name = "MONDAY   " then
  5062.         Target_Day_Position := 2;
  5063.       elsif Day_Name = "TUESDAY  " then
  5064.         Target_Day_Position := 3;
  5065.       elsif Day_Name = "WEDNESDAY" then
  5066.         Target_Day_Position := 4;
  5067.       elsif Day_Name = "THURSDAY " then
  5068.         Target_Day_Position := 5;
  5069.       elsif Day_Name = "FRIDAY   " then
  5070.         Target_Day_Position := 6;
  5071.       else  -- SATURDAY
  5072.         Target_Day_Position := 7;
  5073.       end if;
  5074.  
  5075.       -- Compute the offset.
  5076.  
  5077.       if Current_Day_Position = Target_Day_Position then
  5078.         Offset := 0;
  5079.       elsif Current_Day_Position < Target_Day_Position then
  5080.         Offset := Target_Day_Position - Current_Day_Position;
  5081.       else
  5082.         Offset := (Number_of_Days_in_a_Week - Current_Day_Position) +
  5083.           Target_Day_Position;
  5084.       end if;
  5085.  
  5086.       -- Recompute Return_Time_Value if a future date was specified.
  5087.  
  5088.       for I in 1 .. Offset loop
  5089.         if Seconds /= CALENDAR.DAY_DURATION'FIRST then
  5090.           Return_Time_Value := CALENDAR.TIME_OF (Year, Month, Day, Seconds) +
  5091.             CALENDAR.DAY_DURATION'LAST;
  5092.         else
  5093.           Return_Time_Value := CALENDAR.TIME_OF (Year, Month, Day,
  5094.             CALENDAR.DAY_DURATION'FIRST) + CALENDAR.DAY_DURATION'LAST + 1.0;
  5095.         end if;
  5096.  
  5097.         Year  := CALENDAR.YEAR (Return_Time_Value);
  5098.         Month := CALENDAR.MONTH (Return_Time_Value);
  5099.         Day   := CALENDAR.DAY (Return_Time_Value);
  5100.  
  5101.         if Seconds = CALENDAR.DAY_DURATION'FIRST then
  5102.           Return_Time_Value := CALENDAR.TIME_OF (Year, Month, Day,
  5103.             CALENDAR.DAY_DURATION'FIRST);
  5104.         end if;
  5105.       end loop;
  5106.     end Compute_Current_or_Next_Future_Date_For_a_Day_Name;
  5107.  
  5108.     procedure Perform_Error_Checking_and_Wrap_Up_Loose_Ends is
  5109.     begin
  5110.       -- If a day name and date were specified, make sure that the
  5111.       -- day name is correct for that date.
  5112.  
  5113.       if Tokens_Specified_Array (Day_as_Name)   and
  5114.          Tokens_Specified_Array (Day_as_Number) and
  5115.          Compute_Day_of_Week (CALENDAR.TIME_OF (Year, Month, Day,
  5116.            Seconds)) /= Day_Name then
  5117.         raise Day_Date_Error;
  5118.       end if;
  5119.  
  5120.       -- Make sure that if a special format token was specified, that
  5121.       -- the date was not also specified.
  5122.  
  5123.       if (Tokens_Specified_Array (Special_Format))      and
  5124.          (Tokens_Specified_Array (Day_as_Name)           or
  5125.           Tokens_Specified_Array (Day_as_Number)         or
  5126.           Tokens_Specified_Array (Month_Name_or_Number)  or
  5127.           Tokens_Specified_Array (Year_Number)) then
  5128.         raise External_Representation_Error;
  5129.       end if;
  5130.  
  5131.       -- Make sure that if any part of a date token was specified, that
  5132.       -- at least the day number and month were specified.
  5133.  
  5134.       if Tokens_Specified_Array (Day_as_Number)              and
  5135.          (not Tokens_Specified_Array (Month_Name_or_Number)) then
  5136.         raise Month_Missing_Error;
  5137.       elsif Tokens_Specified_Array (Month_Name_or_Number)    and
  5138.             (not Tokens_Specified_Array (Day_as_Number)) then
  5139.         raise Day_Number_Missing_Error;
  5140.       elsif Tokens_Specified_Array (Year_Number)             and
  5141.             ((not Tokens_Specified_Array (Month_Name_or_Number)) or
  5142.              (not Tokens_Specified_Array (Day_as_Number))) then
  5143.         raise External_Representation_Error;
  5144.       end if;
  5145.  
  5146.       -- Now set the internal time if a date or time token was found.
  5147.  
  5148.       if Tokens_Specified_Array (Day_as_Number) or
  5149.          Tokens_Specified_Array (Time_String) then
  5150.         Return_Time_Value := CALENDAR.TIME_OF (Year, Month, Day, Seconds);
  5151.       end if;
  5152.  
  5153.       -- If the day name was specified without a date, then compute the
  5154.       -- current or next future internal time format as of that day.
  5155.  
  5156.       if Tokens_Specified_Array (Day_as_Name) and
  5157.          (not Tokens_Specified_Array (Day_as_Number)) then
  5158.         Compute_Current_or_Next_Future_Date_For_a_Day_Name;
  5159.       end if;
  5160.     end Perform_Error_Checking_and_Wrap_Up_Loose_Ends;
  5161.   begin  -- Convert
  5162.     -- Check for a null array... let's not deal with it.
  5163.  
  5164.     if Tod_Value'LENGTH = 0 then
  5165.       raise External_Representation_Error;
  5166.     end if;
  5167.  
  5168.     -- Compress the external representation, that is, eliminate all
  5169.     -- unnecessary blanks and/or commas.  Then convert all lower case
  5170.     -- letters to upper case.
  5171.  
  5172.     Compress_External_Representation (Tod_Value, Tod_Value_Compressed_Length);
  5173.     Convert_External_Representation_to_Upper_Case (Tod_Value);
  5174.  
  5175.     if Tod_Value_Compressed_Length < Minimum_Tod_String_Length then
  5176.       raise External_Representation_Error;
  5177.     end if;
  5178.  
  5179.     -- Now loop on all tokens in the external representation.  Analyze
  5180.     -- and process each token.  Some error checking may be needed
  5181.     -- after all tokens are found.
  5182.  
  5183.     loop
  5184.       Grab_a_Token (Tod_Value, Tod_Value_Pointer, Token, Token_Length,
  5185.         No_Token_Found);
  5186.  
  5187.       exit when No_Token_Found;
  5188.  
  5189.       Analyze_and_Process_Token (Token, Token_Length, FALSE);
  5190.     end loop;
  5191.  
  5192.     -- Now perform special error checking and wrap up loose ends.
  5193.  
  5194.     Perform_Error_Checking_and_Wrap_Up_Loose_Ends;
  5195.  
  5196.     -- Now return the CALENDAR.TIME internal representation.  If
  5197.     -- during the processing, CALENDAR.TIME_ERROR was raised, then
  5198.     -- we trap it and send back Date_Error.  If any other exception
  5199.     -- was raised, we do nothing and instead let the caller handle it.
  5200.  
  5201.     return Return_Time_Value;
  5202.   exception
  5203.     when CALENDAR.TIME_ERROR => raise Date_Error;
  5204.   end Convert;
  5205. end Tod_Utilities;
  5206.